github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/core/container/dockercontroller/dockercontroller_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package dockercontroller
    18  
    19  import (
    20  	"archive/tar"
    21  	"bytes"
    22  	"compress/gzip"
    23  	"context"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"os"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/fsouza/go-dockerclient"
    32  	"github.com/spf13/viper"
    33  	"github.com/stretchr/testify/assert"
    34  
    35  	"github.com/hyperledger/fabric/common/ledger/testutil"
    36  	"github.com/hyperledger/fabric/common/util"
    37  	"github.com/hyperledger/fabric/core/chaincode/platforms"
    38  	"github.com/hyperledger/fabric/core/container/ccintf"
    39  	coreutil "github.com/hyperledger/fabric/core/testutil"
    40  	pb "github.com/hyperledger/fabric/protos/peer"
    41  )
    42  
    43  func TestHostConfig(t *testing.T) {
    44  	coreutil.SetupTestConfig()
    45  	var hostConfig = new(docker.HostConfig)
    46  	err := viper.UnmarshalKey("vm.docker.hostConfig", hostConfig)
    47  	if err != nil {
    48  		t.Fatalf("Load docker HostConfig wrong, error: %s", err.Error())
    49  	}
    50  	testutil.AssertNotEquals(t, hostConfig.LogConfig, nil)
    51  	testutil.AssertEquals(t, hostConfig.LogConfig.Type, "json-file")
    52  	testutil.AssertEquals(t, hostConfig.LogConfig.Config["max-size"], "50m")
    53  	testutil.AssertEquals(t, hostConfig.LogConfig.Config["max-file"], "5")
    54  }
    55  
    56  func TestGetDockerHostConfig(t *testing.T) {
    57  	os.Setenv("CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE", "overlay")
    58  	os.Setenv("CORE_VM_DOCKER_HOSTCONFIG_CPUSHARES", fmt.Sprint(1024*1024*1024*2))
    59  	coreutil.SetupTestConfig()
    60  	hostConfig := getDockerHostConfig()
    61  	testutil.AssertNotNil(t, hostConfig)
    62  	testutil.AssertEquals(t, hostConfig.NetworkMode, "overlay")
    63  	testutil.AssertEquals(t, hostConfig.LogConfig.Type, "json-file")
    64  	testutil.AssertEquals(t, hostConfig.LogConfig.Config["max-size"], "50m")
    65  	testutil.AssertEquals(t, hostConfig.LogConfig.Config["max-file"], "5")
    66  	testutil.AssertEquals(t, hostConfig.Memory, int64(1024*1024*1024*2))
    67  	testutil.AssertEquals(t, hostConfig.CPUShares, int64(1024*1024*1024*2))
    68  }
    69  
    70  func Test_Deploy(t *testing.T) {
    71  	dvm := DockerVM{}
    72  	ccid := ccintf.CCID{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "simple"}}}
    73  	//get the tarball for codechain
    74  	tarRdr := getCodeChainBytesInMem()
    75  	args := make([]string, 1)
    76  	env := make([]string, 1)
    77  	ctx := context.Background()
    78  
    79  	// getMockClient returns error
    80  	getClientErr = true
    81  	dvm.getClientFnc = getMockClient
    82  	err := dvm.Deploy(ctx, ccid, args, env, tarRdr)
    83  	testerr(t, err, false)
    84  	getClientErr = false
    85  
    86  	// Failure case: dockerClient.BuildImage returns error
    87  	buildErr = true
    88  	dvm.getClientFnc = getMockClient
    89  	err = dvm.Deploy(ctx, ccid, args, env, tarRdr)
    90  	testerr(t, err, false)
    91  	buildErr = false
    92  
    93  	// Success case
    94  	err = dvm.Deploy(ctx, ccid, args, env, tarRdr)
    95  	testerr(t, err, true)
    96  }
    97  
    98  func Test_Start(t *testing.T) {
    99  	dvm := DockerVM{}
   100  	ccid := ccintf.CCID{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "simple"}}}
   101  	args := make([]string, 1)
   102  	env := make([]string, 1)
   103  	ctx := context.Background()
   104  
   105  	// Failure cases
   106  	// case 1: getMockClient returns error
   107  	dvm.getClientFnc = getMockClient
   108  	getClientErr = true
   109  	err := dvm.Start(ctx, ccid, args, env, nil)
   110  	testerr(t, err, false)
   111  	getClientErr = false
   112  
   113  	// case 2: dockerClient.CreateContainer returns error
   114  	createErr = true
   115  	err = dvm.Start(ctx, ccid, args, env, nil)
   116  	testerr(t, err, false)
   117  	createErr = false
   118  
   119  	// case 3: dockerClient.CreateContainer returns docker.noSuchImgErr
   120  	noSuchImgErr = true
   121  	err = dvm.Start(ctx, ccid, args, env, nil)
   122  	testerr(t, err, false)
   123  
   124  	chaincodePath := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01"
   125  	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG,
   126  		ChaincodeId: &pb.ChaincodeID{Name: "ex01", Path: chaincodePath},
   127  		Input:       &pb.ChaincodeInput{Args: util.ToChaincodeArgs("f")}}
   128  	codePackage, err := platforms.GetDeploymentPayload(spec)
   129  	if err != nil {
   130  		t.Fatal()
   131  	}
   132  	cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackage}
   133  	bldr := func() (io.Reader, error) { return platforms.GenerateDockerBuild(cds) }
   134  
   135  	// case 4: start called with builder and dockerClient.CreateContainer returns
   136  	// docker.noSuchImgErr and dockerClient.Start returns error
   137  	viper.Set("vm.docker.attachStdout", true)
   138  	startErr = true
   139  	err = dvm.Start(ctx, ccid, args, env, bldr)
   140  	testerr(t, err, false)
   141  	startErr = false
   142  
   143  	// Success cases
   144  	err = dvm.Start(ctx, ccid, args, env, bldr)
   145  	testerr(t, err, true)
   146  	noSuchImgErr = false
   147  
   148  	// dockerClient.StopContainer returns error
   149  	stopErr = true
   150  	err = dvm.Start(ctx, ccid, args, env, nil)
   151  	testerr(t, err, true)
   152  	stopErr = false
   153  
   154  	// dockerClient.KillContainer returns error
   155  	killErr = true
   156  	err = dvm.Start(ctx, ccid, args, env, nil)
   157  	testerr(t, err, true)
   158  	killErr = false
   159  
   160  	// dockerClient.RemoveContainer returns error
   161  	removeErr = true
   162  	err = dvm.Start(ctx, ccid, args, env, nil)
   163  	testerr(t, err, true)
   164  	removeErr = false
   165  
   166  	err = dvm.Start(ctx, ccid, args, env, nil)
   167  	testerr(t, err, true)
   168  }
   169  
   170  func Test_Stop(t *testing.T) {
   171  	dvm := DockerVM{}
   172  	ccid := ccintf.CCID{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "simple"}}}
   173  	ctx := context.Background()
   174  
   175  	// Failure case: getMockClient returns error
   176  	getClientErr = true
   177  	dvm.getClientFnc = getMockClient
   178  	err := dvm.Stop(ctx, ccid, 10, true, true)
   179  	testerr(t, err, false)
   180  	getClientErr = false
   181  
   182  	// Success case
   183  	err = dvm.Stop(ctx, ccid, 10, true, true)
   184  	testerr(t, err, true)
   185  }
   186  
   187  func Test_Destroy(t *testing.T) {
   188  	dvm := DockerVM{}
   189  	ccid := ccintf.CCID{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "simple"}}}
   190  	ctx := context.Background()
   191  
   192  	// Failure cases
   193  	// Case 1: getMockClient returns error
   194  	getClientErr = true
   195  	dvm.getClientFnc = getMockClient
   196  	err := dvm.Destroy(ctx, ccid, true, true)
   197  	testerr(t, err, false)
   198  	getClientErr = false
   199  
   200  	// Case 2: dockerClient.RemoveImageExtended returns error
   201  	removeImgErr = true
   202  	err = dvm.Destroy(ctx, ccid, true, true)
   203  	testerr(t, err, false)
   204  	removeImgErr = false
   205  
   206  	// Success case
   207  	err = dvm.Destroy(ctx, ccid, true, true)
   208  	testerr(t, err, true)
   209  }
   210  
   211  func getCodeChainBytesInMem() io.Reader {
   212  	startTime := time.Now()
   213  	inputbuf := bytes.NewBuffer(nil)
   214  	gw := gzip.NewWriter(inputbuf)
   215  	tr := tar.NewWriter(gw)
   216  	dockerFileContents := []byte("FROM busybox:latest\n\nCMD echo hello")
   217  	dockerFileSize := int64(len([]byte(dockerFileContents)))
   218  
   219  	tr.WriteHeader(&tar.Header{Name: "Dockerfile", Size: dockerFileSize,
   220  		ModTime: startTime, AccessTime: startTime, ChangeTime: startTime})
   221  	tr.Write([]byte(dockerFileContents))
   222  	tr.Close()
   223  	gw.Close()
   224  	return inputbuf
   225  }
   226  
   227  func testerr(t *testing.T, err error, succ bool) {
   228  	if succ {
   229  		assert.NoError(t, err, "Expected success but got error")
   230  	} else {
   231  		assert.Error(t, err, "Expected failure but succeeded")
   232  	}
   233  }
   234  
   235  func getMockClient() (dockerClient, error) {
   236  	if getClientErr {
   237  		return nil, errors.New("Failed to get client")
   238  	}
   239  	return &mockClient{noSuchImgErrReturned: false}, nil
   240  }
   241  
   242  type mockClient struct {
   243  	noSuchImgErrReturned bool
   244  }
   245  
   246  var getClientErr, createErr, noSuchImgErr, buildErr, removeImgErr,
   247  	startErr, stopErr, killErr, removeErr bool
   248  
   249  func (c *mockClient) CreateContainer(options docker.CreateContainerOptions) (*docker.Container, error) {
   250  	if createErr {
   251  		return nil, errors.New("Error creating the container")
   252  	} else if noSuchImgErr && !c.noSuchImgErrReturned {
   253  		c.noSuchImgErrReturned = true
   254  		return nil, docker.ErrNoSuchImage
   255  	}
   256  	return &docker.Container{}, nil
   257  }
   258  
   259  func (c *mockClient) StartContainer(id string, cfg *docker.HostConfig) error {
   260  	if startErr {
   261  		return errors.New("Error starting the container")
   262  	}
   263  	return nil
   264  }
   265  
   266  func (c *mockClient) AttachToContainer(opts docker.AttachToContainerOptions) error {
   267  	if opts.Success != nil {
   268  		opts.Success <- struct{}{}
   269  	}
   270  	return nil
   271  }
   272  
   273  func (c *mockClient) BuildImage(opts docker.BuildImageOptions) error {
   274  	if buildErr {
   275  		return errors.New("Error building image")
   276  	}
   277  	return nil
   278  }
   279  
   280  func (c *mockClient) RemoveImageExtended(id string, opts docker.RemoveImageOptions) error {
   281  	if removeImgErr {
   282  		return errors.New("Error removing extended image")
   283  	}
   284  	return nil
   285  }
   286  
   287  func (c *mockClient) StopContainer(id string, timeout uint) error {
   288  	if stopErr {
   289  		return errors.New("Error stopping container")
   290  	}
   291  	return nil
   292  }
   293  
   294  func (c *mockClient) KillContainer(opts docker.KillContainerOptions) error {
   295  	if killErr {
   296  		return errors.New("Error killing container")
   297  	}
   298  	return nil
   299  }
   300  
   301  func (c *mockClient) RemoveContainer(opts docker.RemoveContainerOptions) error {
   302  	if removeErr {
   303  		return errors.New("Error removing container")
   304  	}
   305  	return nil
   306  }