package client import ( "bytes" "encoding/json" "io/ioutil" "net/http" "net/url" "os" "runtime" "strings" "testing" "github.com/docker/docker/api/types" "golang.org/x/net/context" ) func TestNewEnvClient(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping unix only test for windows") } cases := []struct { envs map[string]string expectedError string expectedVersion string }{ { envs: map[string]string{}, expectedVersion: DefaultVersion, }, { envs: map[string]string{ "DOCKER_CERT_PATH": "invalid/path", }, expectedError: "Could not load X509 key pair: open invalid/path/cert.pem: no such file or directory. Make sure the key is not encrypted", }, { envs: map[string]string{ "DOCKER_CERT_PATH": "testdata/", }, expectedVersion: DefaultVersion, }, { envs: map[string]string{ "DOCKER_CERT_PATH": "testdata/", "DOCKER_TLS_VERIFY": "1", }, expectedVersion: DefaultVersion, }, { envs: map[string]string{ "DOCKER_CERT_PATH": "testdata/", "DOCKER_HOST": "https://notaunixsocket", }, expectedVersion: DefaultVersion, }, { envs: map[string]string{ "DOCKER_HOST": "host", }, expectedError: "unable to parse docker host `host`", }, { envs: map[string]string{ "DOCKER_HOST": "invalid://url", }, expectedVersion: DefaultVersion, }, { envs: map[string]string{ "DOCKER_API_VERSION": "anything", }, expectedVersion: "anything", }, { envs: map[string]string{ "DOCKER_API_VERSION": "1.22", }, expectedVersion: "1.22", }, } for _, c := range cases { recoverEnvs := setupEnvs(t, c.envs) apiclient, err := NewEnvClient() if c.expectedError != "" { if err == nil { t.Errorf("expected an error for %v", c) } else if err.Error() != c.expectedError { t.Errorf("expected an error %s, got %s, for %v", c.expectedError, err.Error(), c) } } else { if err != nil { t.Error(err) } version := apiclient.ClientVersion() if version != c.expectedVersion { t.Errorf("expected %s, got %s, for %v", c.expectedVersion, version, c) } } if c.envs["DOCKER_TLS_VERIFY"] != "" { // pedantic checking that this is handled correctly tr := apiclient.client.Transport.(*http.Transport) if tr.TLSClientConfig == nil { t.Error("no TLS config found when DOCKER_TLS_VERIFY enabled") } if tr.TLSClientConfig.InsecureSkipVerify { t.Error("TLS verification should be enabled") } } recoverEnvs(t) } } func setupEnvs(t *testing.T, envs map[string]string) func(*testing.T) { oldEnvs := map[string]string{} for key, value := range envs { oldEnv := os.Getenv(key) oldEnvs[key] = oldEnv err := os.Setenv(key, value) if err != nil { t.Error(err) } } return func(t *testing.T) { for key, value := range oldEnvs { err := os.Setenv(key, value) if err != nil { t.Error(err) } } } } func TestGetAPIPath(t *testing.T) { cases := []struct { v string p string q url.Values e string }{ {"", "/containers/json", nil, "/containers/json"}, {"", "/containers/json", url.Values{}, "/containers/json"}, {"", "/containers/json", url.Values{"s": []string{"c"}}, "/containers/json?s=c"}, {"1.22", "/containers/json", nil, "/v1.22/containers/json"}, {"1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"}, {"1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"}, {"v1.22", "/containers/json", nil, "/v1.22/containers/json"}, {"v1.22", "/containers/json", url.Values{}, "/v1.22/containers/json"}, {"v1.22", "/containers/json", url.Values{"s": []string{"c"}}, "/v1.22/containers/json?s=c"}, {"v1.22", "/networks/kiwl$%^", nil, "/v1.22/networks/kiwl$%25%5E"}, } for _, cs := range cases { c, err := NewClient("unix:///var/run/docker.sock", cs.v, nil, nil) if err != nil { t.Fatal(err) } g := c.getAPIPath(cs.p, cs.q) if g != cs.e { t.Fatalf("Expected %s, got %s", cs.e, g) } err = c.Close() if nil != err { t.Fatalf("close client failed, error message: %s", err) } } } func TestParseHost(t *testing.T) { cases := []struct { host string proto string addr string base string err bool }{ {"", "", "", "", true}, {"foobar", "", "", "", true}, {"foo://bar", "foo", "bar", "", false}, {"tcp://localhost:2476", "tcp", "localhost:2476", "", false}, {"tcp://localhost:2476/path", "tcp", "localhost:2476", "/path", false}, } for _, cs := range cases { p, a, b, e := ParseHost(cs.host) if cs.err && e == nil { t.Fatalf("expected error, got nil") } if !cs.err && e != nil { t.Fatal(e) } if cs.proto != p { t.Fatalf("expected proto %s, got %s", cs.proto, p) } if cs.addr != a { t.Fatalf("expected addr %s, got %s", cs.addr, a) } if cs.base != b { t.Fatalf("expected base %s, got %s", cs.base, b) } } } func TestUpdateClientVersion(t *testing.T) { client := &Client{ client: newMockClient(func(req *http.Request) (*http.Response, error) { splitQuery := strings.Split(req.URL.Path, "/") queryVersion := splitQuery[1] b, err := json.Marshal(types.Version{ APIVersion: queryVersion, }) if err != nil { return nil, err } return &http.Response{ StatusCode: http.StatusOK, Body: ioutil.NopCloser(bytes.NewReader(b)), }, nil }), } cases := []struct { v string }{ {"1.20"}, {"v1.21"}, {"1.22"}, {"v1.22"}, } for _, cs := range cases { client.UpdateClientVersion(cs.v) r, err := client.ServerVersion(context.Background()) if err != nil { t.Fatal(err) } if strings.TrimPrefix(r.APIVersion, "v") != strings.TrimPrefix(cs.v, "v") { t.Fatalf("Expected %s, got %s", cs.v, r.APIVersion) } } } func TestNewEnvClientSetsDefaultVersion(t *testing.T) { // Unset environment variables envVarKeys := []string{ "DOCKER_HOST", "DOCKER_API_VERSION", "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH", } envVarValues := make(map[string]string) for _, key := range envVarKeys { envVarValues[key] = os.Getenv(key) os.Setenv(key, "") } client, err := NewEnvClient() if err != nil { t.Fatal(err) } if client.version != DefaultVersion { t.Fatalf("Expected %s, got %s", DefaultVersion, client.version) } expected := "1.22" os.Setenv("DOCKER_API_VERSION", expected) client, err = NewEnvClient() if err != nil { t.Fatal(err) } if client.version != expected { t.Fatalf("Expected %s, got %s", expected, client.version) } // Restore environment variables for _, key := range envVarKeys { os.Setenv(key, envVarValues[key]) } }