github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/command/cli_test.go (about)

     1  package command
     2  
     3  import (
     4  	"context"
     5  	"crypto/x509"
     6  	"os"
     7  	"runtime"
     8  	"testing"
     9  
    10  	cliconfig "github.com/docker/cli/cli/config"
    11  	"github.com/docker/cli/cli/config/configfile"
    12  	"github.com/docker/cli/cli/flags"
    13  	"github.com/docker/docker/api"
    14  	"github.com/docker/docker/api/types"
    15  	"github.com/docker/docker/client"
    16  	"github.com/pkg/errors"
    17  	"gotest.tools/assert"
    18  	is "gotest.tools/assert/cmp"
    19  	"gotest.tools/env"
    20  	"gotest.tools/fs"
    21  )
    22  
    23  func TestNewAPIClientFromFlags(t *testing.T) {
    24  	host := "unix://path"
    25  	if runtime.GOOS == "windows" {
    26  		host = "npipe://./"
    27  	}
    28  	opts := &flags.CommonOptions{Hosts: []string{host}}
    29  	configFile := &configfile.ConfigFile{
    30  		HTTPHeaders: map[string]string{
    31  			"My-Header": "Custom-Value",
    32  		},
    33  	}
    34  	apiclient, err := NewAPIClientFromFlags(opts, configFile)
    35  	assert.NilError(t, err)
    36  	assert.Check(t, is.Equal(host, apiclient.DaemonHost()))
    37  
    38  	expectedHeaders := map[string]string{
    39  		"My-Header":  "Custom-Value",
    40  		"User-Agent": UserAgent(),
    41  	}
    42  	assert.Check(t, is.DeepEqual(expectedHeaders, apiclient.(*client.Client).CustomHTTPHeaders()))
    43  	assert.Check(t, is.Equal(api.DefaultVersion, apiclient.ClientVersion()))
    44  }
    45  
    46  func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
    47  	customVersion := "v3.3.3"
    48  	defer env.Patch(t, "DOCKER_API_VERSION", customVersion)()
    49  
    50  	opts := &flags.CommonOptions{}
    51  	configFile := &configfile.ConfigFile{}
    52  	apiclient, err := NewAPIClientFromFlags(opts, configFile)
    53  	assert.NilError(t, err)
    54  	assert.Check(t, is.Equal(customVersion, apiclient.ClientVersion()))
    55  }
    56  
    57  type fakeClient struct {
    58  	client.Client
    59  	pingFunc   func() (types.Ping, error)
    60  	version    string
    61  	negotiated bool
    62  }
    63  
    64  func (c *fakeClient) Ping(_ context.Context) (types.Ping, error) {
    65  	return c.pingFunc()
    66  }
    67  
    68  func (c *fakeClient) ClientVersion() string {
    69  	return c.version
    70  }
    71  
    72  func (c *fakeClient) NegotiateAPIVersionPing(types.Ping) {
    73  	c.negotiated = true
    74  }
    75  
    76  func TestInitializeFromClient(t *testing.T) {
    77  	defaultVersion := "v1.55"
    78  
    79  	var testcases = []struct {
    80  		doc            string
    81  		pingFunc       func() (types.Ping, error)
    82  		expectedServer ServerInfo
    83  		negotiated     bool
    84  	}{
    85  		{
    86  			doc: "successful ping",
    87  			pingFunc: func() (types.Ping, error) {
    88  				return types.Ping{Experimental: true, OSType: "linux", APIVersion: "v1.30"}, nil
    89  			},
    90  			expectedServer: ServerInfo{HasExperimental: true, OSType: "linux"},
    91  			negotiated:     true,
    92  		},
    93  		{
    94  			doc: "failed ping, no API version",
    95  			pingFunc: func() (types.Ping, error) {
    96  				return types.Ping{}, errors.New("failed")
    97  			},
    98  			expectedServer: ServerInfo{HasExperimental: true},
    99  		},
   100  		{
   101  			doc: "failed ping, with API version",
   102  			pingFunc: func() (types.Ping, error) {
   103  				return types.Ping{APIVersion: "v1.33"}, errors.New("failed")
   104  			},
   105  			expectedServer: ServerInfo{HasExperimental: true},
   106  			negotiated:     true,
   107  		},
   108  	}
   109  
   110  	for _, testcase := range testcases {
   111  		t.Run(testcase.doc, func(t *testing.T) {
   112  			apiclient := &fakeClient{
   113  				pingFunc: testcase.pingFunc,
   114  				version:  defaultVersion,
   115  			}
   116  
   117  			cli := &DockerCli{client: apiclient}
   118  			cli.initializeFromClient()
   119  			assert.Check(t, is.DeepEqual(testcase.expectedServer, cli.serverInfo))
   120  			assert.Check(t, is.Equal(testcase.negotiated, apiclient.negotiated))
   121  		})
   122  	}
   123  }
   124  
   125  func TestExperimentalCLI(t *testing.T) {
   126  	defaultVersion := "v1.55"
   127  
   128  	var testcases = []struct {
   129  		doc                     string
   130  		configfile              string
   131  		expectedExperimentalCLI bool
   132  	}{
   133  		{
   134  			doc:                     "default",
   135  			configfile:              `{}`,
   136  			expectedExperimentalCLI: false,
   137  		},
   138  		{
   139  			doc: "experimental",
   140  			configfile: `{
   141  	"experimental": "enabled"
   142  }`,
   143  			expectedExperimentalCLI: true,
   144  		},
   145  	}
   146  
   147  	for _, testcase := range testcases {
   148  		t.Run(testcase.doc, func(t *testing.T) {
   149  			dir := fs.NewDir(t, testcase.doc, fs.WithFile("config.json", testcase.configfile))
   150  			defer dir.Remove()
   151  			apiclient := &fakeClient{
   152  				version: defaultVersion,
   153  			}
   154  
   155  			cli := &DockerCli{client: apiclient, err: os.Stderr}
   156  			cliconfig.SetDir(dir.Path())
   157  			err := cli.Initialize(flags.NewClientOptions())
   158  			assert.NilError(t, err)
   159  			assert.Check(t, is.Equal(testcase.expectedExperimentalCLI, cli.ClientInfo().HasExperimental))
   160  		})
   161  	}
   162  }
   163  
   164  func TestGetClientWithPassword(t *testing.T) {
   165  	expected := "password"
   166  
   167  	var testcases = []struct {
   168  		doc             string
   169  		password        string
   170  		retrieverErr    error
   171  		retrieverGiveup bool
   172  		newClientErr    error
   173  		expectedErr     string
   174  	}{
   175  		{
   176  			doc:      "successful connect",
   177  			password: expected,
   178  		},
   179  		{
   180  			doc:             "password retriever exhausted",
   181  			retrieverGiveup: true,
   182  			retrieverErr:    errors.New("failed"),
   183  			expectedErr:     "private key is encrypted, but could not get passphrase",
   184  		},
   185  		{
   186  			doc:          "password retriever error",
   187  			retrieverErr: errors.New("failed"),
   188  			expectedErr:  "failed",
   189  		},
   190  		{
   191  			doc:          "newClient error",
   192  			newClientErr: errors.New("failed to connect"),
   193  			expectedErr:  "failed to connect",
   194  		},
   195  	}
   196  
   197  	for _, testcase := range testcases {
   198  		t.Run(testcase.doc, func(t *testing.T) {
   199  			passRetriever := func(_, _ string, _ bool, attempts int) (passphrase string, giveup bool, err error) {
   200  				// Always return an invalid pass first to test iteration
   201  				switch attempts {
   202  				case 0:
   203  					return "something else", false, nil
   204  				default:
   205  					return testcase.password, testcase.retrieverGiveup, testcase.retrieverErr
   206  				}
   207  			}
   208  
   209  			newClient := func(currentPassword string) (client.APIClient, error) {
   210  				if testcase.newClientErr != nil {
   211  					return nil, testcase.newClientErr
   212  				}
   213  				if currentPassword == expected {
   214  					return &client.Client{}, nil
   215  				}
   216  				return &client.Client{}, x509.IncorrectPasswordError
   217  			}
   218  
   219  			_, err := getClientWithPassword(passRetriever, newClient)
   220  			if testcase.expectedErr != "" {
   221  				assert.ErrorContains(t, err, testcase.expectedErr)
   222  				return
   223  			}
   224  
   225  			assert.NilError(t, err)
   226  		})
   227  	}
   228  }