github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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, 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, 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, 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, nil)
   140  	testerr(t, err, false)
   141  	startErr = false
   142  
   143  	// Success cases
   144  	err = dvm.Start(ctx, ccid, args, env, bldr, nil)
   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, 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, 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, nil)
   163  	testerr(t, err, true)
   164  	removeErr = false
   165  
   166  	err = dvm.Start(ctx, ccid, args, env, nil, nil)
   167  	testerr(t, err, true)
   168  
   169  	//test preLaunchFunc works correctly
   170  	preLaunchStr := "notset"
   171  	preLaunchFunc := func() error {
   172  		preLaunchStr = "set"
   173  		return nil
   174  	}
   175  
   176  	err = dvm.Start(ctx, ccid, args, env, nil, preLaunchFunc)
   177  	testerr(t, err, true)
   178  	assert.Equal(t, preLaunchStr, "set")
   179  
   180  	preLaunchFunc = func() error {
   181  		return fmt.Errorf("testing error path")
   182  	}
   183  
   184  	err = dvm.Start(ctx, ccid, args, env, nil, preLaunchFunc)
   185  	testerr(t, err, false)
   186  }
   187  
   188  func Test_Stop(t *testing.T) {
   189  	dvm := DockerVM{}
   190  	ccid := ccintf.CCID{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "simple"}}}
   191  	ctx := context.Background()
   192  
   193  	// Failure case: getMockClient returns error
   194  	getClientErr = true
   195  	dvm.getClientFnc = getMockClient
   196  	err := dvm.Stop(ctx, ccid, 10, true, true)
   197  	testerr(t, err, false)
   198  	getClientErr = false
   199  
   200  	// Success case
   201  	err = dvm.Stop(ctx, ccid, 10, true, true)
   202  	testerr(t, err, true)
   203  }
   204  
   205  func Test_Destroy(t *testing.T) {
   206  	dvm := DockerVM{}
   207  	ccid := ccintf.CCID{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "simple"}}}
   208  	ctx := context.Background()
   209  
   210  	// Failure cases
   211  	// Case 1: getMockClient returns error
   212  	getClientErr = true
   213  	dvm.getClientFnc = getMockClient
   214  	err := dvm.Destroy(ctx, ccid, true, true)
   215  	testerr(t, err, false)
   216  	getClientErr = false
   217  
   218  	// Case 2: dockerClient.RemoveImageExtended returns error
   219  	removeImgErr = true
   220  	err = dvm.Destroy(ctx, ccid, true, true)
   221  	testerr(t, err, false)
   222  	removeImgErr = false
   223  
   224  	// Success case
   225  	err = dvm.Destroy(ctx, ccid, true, true)
   226  	testerr(t, err, true)
   227  }
   228  
   229  func getCodeChainBytesInMem() io.Reader {
   230  	startTime := time.Now()
   231  	inputbuf := bytes.NewBuffer(nil)
   232  	gw := gzip.NewWriter(inputbuf)
   233  	tr := tar.NewWriter(gw)
   234  	dockerFileContents := []byte("FROM busybox:latest\n\nCMD echo hello")
   235  	dockerFileSize := int64(len([]byte(dockerFileContents)))
   236  
   237  	tr.WriteHeader(&tar.Header{Name: "Dockerfile", Size: dockerFileSize,
   238  		ModTime: startTime, AccessTime: startTime, ChangeTime: startTime})
   239  	tr.Write([]byte(dockerFileContents))
   240  	tr.Close()
   241  	gw.Close()
   242  	return inputbuf
   243  }
   244  
   245  func testerr(t *testing.T, err error, succ bool) {
   246  	if succ {
   247  		assert.NoError(t, err, "Expected success but got error")
   248  	} else {
   249  		assert.Error(t, err, "Expected failure but succeeded")
   250  	}
   251  }
   252  
   253  func getMockClient() (dockerClient, error) {
   254  	if getClientErr {
   255  		return nil, errors.New("Failed to get client")
   256  	}
   257  	return &mockClient{noSuchImgErrReturned: false}, nil
   258  }
   259  
   260  type mockClient struct {
   261  	noSuchImgErrReturned bool
   262  }
   263  
   264  var getClientErr, createErr, noSuchImgErr, buildErr, removeImgErr,
   265  	startErr, stopErr, killErr, removeErr bool
   266  
   267  func (c *mockClient) CreateContainer(options docker.CreateContainerOptions) (*docker.Container, error) {
   268  	if createErr {
   269  		return nil, errors.New("Error creating the container")
   270  	} else if noSuchImgErr && !c.noSuchImgErrReturned {
   271  		c.noSuchImgErrReturned = true
   272  		return nil, docker.ErrNoSuchImage
   273  	}
   274  	return &docker.Container{}, nil
   275  }
   276  
   277  func (c *mockClient) StartContainer(id string, cfg *docker.HostConfig) error {
   278  	if startErr {
   279  		return errors.New("Error starting the container")
   280  	}
   281  	return nil
   282  }
   283  
   284  func (c *mockClient) AttachToContainer(opts docker.AttachToContainerOptions) error {
   285  	if opts.Success != nil {
   286  		opts.Success <- struct{}{}
   287  	}
   288  	return nil
   289  }
   290  
   291  func (c *mockClient) BuildImage(opts docker.BuildImageOptions) error {
   292  	if buildErr {
   293  		return errors.New("Error building image")
   294  	}
   295  	return nil
   296  }
   297  
   298  func (c *mockClient) RemoveImageExtended(id string, opts docker.RemoveImageOptions) error {
   299  	if removeImgErr {
   300  		return errors.New("Error removing extended image")
   301  	}
   302  	return nil
   303  }
   304  
   305  func (c *mockClient) StopContainer(id string, timeout uint) error {
   306  	if stopErr {
   307  		return errors.New("Error stopping container")
   308  	}
   309  	return nil
   310  }
   311  
   312  func (c *mockClient) KillContainer(opts docker.KillContainerOptions) error {
   313  	if killErr {
   314  		return errors.New("Error killing container")
   315  	}
   316  	return nil
   317  }
   318  
   319  func (c *mockClient) RemoveContainer(opts docker.RemoveContainerOptions) error {
   320  	if removeErr {
   321  		return errors.New("Error removing container")
   322  	}
   323  	return nil
   324  }