2017-08-18 12:49:23 -04:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
2019-01-28 08:52:58 -05:00
|
|
|
"bytes"
|
2018-05-03 21:02:44 -04:00
|
|
|
"context"
|
2019-01-28 08:52:58 -05:00
|
|
|
"fmt"
|
2022-02-25 08:35:28 -05:00
|
|
|
"io"
|
2022-06-06 12:23:53 -04:00
|
|
|
"net"
|
2021-07-22 04:28:05 -04:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2017-08-18 12:49:23 -04:00
|
|
|
"os"
|
2022-06-06 12:23:53 -04:00
|
|
|
"path/filepath"
|
2018-02-27 10:54:36 -05:00
|
|
|
"runtime"
|
2021-07-22 04:28:05 -04:00
|
|
|
"strings"
|
2017-08-18 12:49:23 -04:00
|
|
|
"testing"
|
2022-06-06 12:23:53 -04:00
|
|
|
"time"
|
2017-08-18 12:49:23 -04:00
|
|
|
|
2022-03-04 07:24:28 -05:00
|
|
|
"github.com/docker/cli/cli/config"
|
2017-08-18 12:49:23 -04:00
|
|
|
"github.com/docker/cli/cli/config/configfile"
|
|
|
|
"github.com/docker/cli/cli/flags"
|
2024-06-11 10:49:25 -04:00
|
|
|
"github.com/docker/cli/cli/streams"
|
2017-08-18 12:49:23 -04:00
|
|
|
"github.com/docker/docker/api"
|
2017-09-20 16:13:03 -04:00
|
|
|
"github.com/docker/docker/api/types"
|
2017-08-18 12:49:23 -04:00
|
|
|
"github.com/docker/docker/client"
|
2017-09-20 16:13:03 -04:00
|
|
|
"github.com/pkg/errors"
|
2020-02-22 12:12:14 -05:00
|
|
|
"gotest.tools/v3/assert"
|
|
|
|
"gotest.tools/v3/fs"
|
2017-08-18 12:49:23 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestNewAPIClientFromFlags(t *testing.T) {
|
|
|
|
host := "unix://path"
|
2018-02-27 10:54:36 -05:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
host = "npipe://./"
|
|
|
|
}
|
2022-11-04 06:58:11 -04:00
|
|
|
opts := &flags.ClientOptions{Hosts: []string{host}}
|
2021-07-22 04:28:05 -04:00
|
|
|
apiClient, err := NewAPIClientFromFlags(opts, &configfile.ConfigFile{})
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
2021-07-22 04:28:05 -04:00
|
|
|
assert.Equal(t, apiClient.DaemonHost(), host)
|
|
|
|
assert.Equal(t, apiClient.ClientVersion(), api.DefaultVersion)
|
2017-08-18 12:49:23 -04:00
|
|
|
}
|
|
|
|
|
2018-10-16 03:34:54 -04:00
|
|
|
func TestNewAPIClientFromFlagsForDefaultSchema(t *testing.T) {
|
|
|
|
host := ":2375"
|
2021-12-07 08:50:16 -05:00
|
|
|
slug := "tcp://localhost"
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
slug = "tcp://127.0.0.1"
|
|
|
|
}
|
2022-11-04 06:58:11 -04:00
|
|
|
opts := &flags.ClientOptions{Hosts: []string{host}}
|
2021-07-22 04:28:05 -04:00
|
|
|
apiClient, err := NewAPIClientFromFlags(opts, &configfile.ConfigFile{})
|
|
|
|
assert.NilError(t, err)
|
2021-12-07 08:50:16 -05:00
|
|
|
assert.Equal(t, apiClient.DaemonHost(), slug+host)
|
2021-07-22 04:28:05 -04:00
|
|
|
assert.Equal(t, apiClient.ClientVersion(), api.DefaultVersion)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewAPIClientFromFlagsWithCustomHeaders(t *testing.T) {
|
|
|
|
var received map[string]string
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
received = map[string]string{
|
|
|
|
"My-Header": r.Header.Get("My-Header"),
|
|
|
|
"User-Agent": r.Header.Get("User-Agent"),
|
|
|
|
}
|
|
|
|
_, _ = w.Write([]byte("OK"))
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
host := strings.Replace(ts.URL, "http://", "tcp://", 1)
|
2022-11-04 06:58:11 -04:00
|
|
|
opts := &flags.ClientOptions{Hosts: []string{host}}
|
2018-10-16 03:34:54 -04:00
|
|
|
configFile := &configfile.ConfigFile{
|
|
|
|
HTTPHeaders: map[string]string{
|
|
|
|
"My-Header": "Custom-Value",
|
|
|
|
},
|
|
|
|
}
|
2021-07-22 04:28:05 -04:00
|
|
|
|
|
|
|
apiClient, err := NewAPIClientFromFlags(opts, configFile)
|
2018-10-16 03:34:54 -04:00
|
|
|
assert.NilError(t, err)
|
2021-07-22 04:28:05 -04:00
|
|
|
assert.Equal(t, apiClient.DaemonHost(), host)
|
|
|
|
assert.Equal(t, apiClient.ClientVersion(), api.DefaultVersion)
|
|
|
|
|
|
|
|
// verify User-Agent is not appended to the configfile. see https://github.com/docker/cli/pull/2756
|
|
|
|
assert.DeepEqual(t, configFile.HTTPHeaders, map[string]string{"My-Header": "Custom-Value"})
|
2018-10-16 03:34:54 -04:00
|
|
|
|
|
|
|
expectedHeaders := map[string]string{
|
|
|
|
"My-Header": "Custom-Value",
|
|
|
|
"User-Agent": UserAgent(),
|
|
|
|
}
|
2021-07-22 04:28:05 -04:00
|
|
|
_, err = apiClient.Ping(context.Background())
|
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.DeepEqual(t, received, expectedHeaders)
|
2018-10-16 03:34:54 -04:00
|
|
|
}
|
|
|
|
|
2024-05-31 07:04:52 -04:00
|
|
|
func TestNewAPIClientFromFlagsWithCustomHeadersFromEnv(t *testing.T) {
|
|
|
|
var received http.Header
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
received = r.Header.Clone()
|
|
|
|
_, _ = w.Write([]byte("OK"))
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
host := strings.Replace(ts.URL, "http://", "tcp://", 1)
|
|
|
|
opts := &flags.ClientOptions{Hosts: []string{host}}
|
|
|
|
configFile := &configfile.ConfigFile{
|
|
|
|
HTTPHeaders: map[string]string{
|
|
|
|
"My-Header": "Custom-Value from config-file",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// envOverrideHTTPHeaders should override the HTTPHeaders from the config-file,
|
|
|
|
// so "My-Header" should not be present.
|
|
|
|
t.Setenv(envOverrideHTTPHeaders, `one=one-value,"two=two,value",three=,four=four-value,four=four-value-override`)
|
|
|
|
apiClient, err := NewAPIClientFromFlags(opts, configFile)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Equal(t, apiClient.DaemonHost(), host)
|
|
|
|
assert.Equal(t, apiClient.ClientVersion(), api.DefaultVersion)
|
|
|
|
|
|
|
|
expectedHeaders := http.Header{
|
|
|
|
"One": []string{"one-value"},
|
|
|
|
"Two": []string{"two,value"},
|
|
|
|
"Three": []string{""},
|
|
|
|
"Four": []string{"four-value-override"},
|
|
|
|
"User-Agent": []string{UserAgent()},
|
|
|
|
}
|
|
|
|
_, err = apiClient.Ping(context.Background())
|
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.DeepEqual(t, received, expectedHeaders)
|
|
|
|
}
|
|
|
|
|
2017-08-18 12:49:23 -04:00
|
|
|
func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
|
|
|
|
customVersion := "v3.3.3"
|
2022-09-22 10:31:28 -04:00
|
|
|
t.Setenv("DOCKER_API_VERSION", customVersion)
|
|
|
|
t.Setenv("DOCKER_HOST", ":2375")
|
2017-08-18 12:49:23 -04:00
|
|
|
|
2022-11-04 06:58:11 -04:00
|
|
|
opts := &flags.ClientOptions{}
|
2017-08-18 12:49:23 -04:00
|
|
|
configFile := &configfile.ConfigFile{}
|
|
|
|
apiclient, err := NewAPIClientFromFlags(opts, configFile)
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
2021-07-22 04:28:05 -04:00
|
|
|
assert.Equal(t, apiclient.ClientVersion(), customVersion)
|
2017-08-18 12:49:23 -04:00
|
|
|
}
|
|
|
|
|
2017-09-20 16:13:03 -04:00
|
|
|
type fakeClient struct {
|
|
|
|
client.Client
|
|
|
|
pingFunc func() (types.Ping, error)
|
|
|
|
version string
|
|
|
|
negotiated bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *fakeClient) Ping(_ context.Context) (types.Ping, error) {
|
|
|
|
return c.pingFunc()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *fakeClient) ClientVersion() string {
|
|
|
|
return c.version
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *fakeClient) NegotiateAPIVersionPing(types.Ping) {
|
|
|
|
c.negotiated = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInitializeFromClient(t *testing.T) {
|
2022-11-04 10:47:14 -04:00
|
|
|
const defaultVersion = "v1.55"
|
2017-09-20 16:13:03 -04:00
|
|
|
|
2022-09-29 11:21:51 -04:00
|
|
|
testcases := []struct {
|
2017-09-20 16:13:03 -04:00
|
|
|
doc string
|
|
|
|
pingFunc func() (types.Ping, error)
|
|
|
|
expectedServer ServerInfo
|
|
|
|
negotiated bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
doc: "successful ping",
|
|
|
|
pingFunc: func() (types.Ping, error) {
|
|
|
|
return types.Ping{Experimental: true, OSType: "linux", APIVersion: "v1.30"}, nil
|
|
|
|
},
|
|
|
|
expectedServer: ServerInfo{HasExperimental: true, OSType: "linux"},
|
|
|
|
negotiated: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "failed ping, no API version",
|
|
|
|
pingFunc: func() (types.Ping, error) {
|
|
|
|
return types.Ping{}, errors.New("failed")
|
|
|
|
},
|
|
|
|
expectedServer: ServerInfo{HasExperimental: true},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "failed ping, with API version",
|
|
|
|
pingFunc: func() (types.Ping, error) {
|
|
|
|
return types.Ping{APIVersion: "v1.33"}, errors.New("failed")
|
|
|
|
},
|
|
|
|
expectedServer: ServerInfo{HasExperimental: true},
|
|
|
|
negotiated: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, testcase := range testcases {
|
2019-10-29 09:37:37 -04:00
|
|
|
testcase := testcase
|
2017-09-20 16:13:03 -04:00
|
|
|
t.Run(testcase.doc, func(t *testing.T) {
|
|
|
|
apiclient := &fakeClient{
|
|
|
|
pingFunc: testcase.pingFunc,
|
|
|
|
version: defaultVersion,
|
|
|
|
}
|
|
|
|
|
|
|
|
cli := &DockerCli{client: apiclient}
|
2022-11-04 10:47:14 -04:00
|
|
|
err := cli.Initialize(flags.NewClientOptions())
|
|
|
|
assert.NilError(t, err)
|
2022-03-29 04:41:43 -04:00
|
|
|
assert.DeepEqual(t, cli.ServerInfo(), testcase.expectedServer)
|
2021-07-22 04:28:05 -04:00
|
|
|
assert.Equal(t, apiclient.negotiated, testcase.negotiated)
|
2017-09-20 16:13:03 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 12:23:53 -04:00
|
|
|
// Makes sure we don't hang forever on the initial connection.
|
|
|
|
// https://github.com/docker/cli/issues/3652
|
|
|
|
func TestInitializeFromClientHangs(t *testing.T) {
|
|
|
|
dir := t.TempDir()
|
|
|
|
socket := filepath.Join(dir, "my.sock")
|
|
|
|
l, err := net.Listen("unix", socket)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
receiveReqCh := make(chan bool)
|
|
|
|
timeoutCtx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
// Simulate a server that hangs on connections.
|
|
|
|
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
select {
|
|
|
|
case <-timeoutCtx.Done():
|
|
|
|
case receiveReqCh <- true: // Blocks until someone receives on the channel.
|
|
|
|
}
|
|
|
|
_, _ = w.Write([]byte("OK"))
|
|
|
|
}))
|
|
|
|
ts.Listener = l
|
|
|
|
ts.Start()
|
|
|
|
defer ts.Close()
|
|
|
|
|
linting: fmt.Sprintf can be replaced with string concatenation (perfsprint)
cli/registry/client/endpoint.go:128:34: fmt.Sprintf can be replaced with string concatenation (perfsprint)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
^
cli/command/telemetry_docker.go:88:14: fmt.Sprintf can be replaced with string concatenation (perfsprint)
endpoint = fmt.Sprintf("unix://%s", path.Join(u.Host, u.Path))
^
cli/command/cli_test.go:195:47: fmt.Sprintf can be replaced with string concatenation (perfsprint)
opts := &flags.ClientOptions{Hosts: []string{fmt.Sprintf("unix://%s", socket)}}
^
cli/command/registry_test.go:59:24: fmt.Sprintf can be replaced with string concatenation (perfsprint)
inputServerAddress: fmt.Sprintf("https://%s", testAuthConfigs[1].ServerAddress),
^
cli/command/container/opts_test.go:338:35: fmt.Sprintf can be replaced with string concatenation (perfsprint)
if config, _, _ := mustParse(t, fmt.Sprintf("--hostname=%s", hostname)); config.Hostname != expectedHostname {
^
cli/command/context/options.go:79:24: fmt.Sprintf can be replaced with string concatenation (perfsprint)
errs = append(errs, fmt.Sprintf("%s: unrecognized config key", k))
^
cli/command/image/build.go:461:68: fmt.Sprintf can be replaced with string concatenation (perfsprint)
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", reference.FamiliarString(trustedRef)))
^
cli/command/image/remove_test.go:21:9: fmt.Sprintf can be replaced with string concatenation (perfsprint)
return fmt.Sprintf("Error: No such image: %s", n.imageID)
^
cli/command/image/build/context.go:229:102: fmt.Sprintf can be replaced with string concatenation (perfsprint)
progReader := progress.NewProgressReader(response.Body, progressOutput, response.ContentLength, "", fmt.Sprintf("Downloading build context from remote url: %s", remoteURL))
^
cli/command/service/logs.go:215:16: fmt.Sprintf can be replaced with string concatenation (perfsprint)
taskName += fmt.Sprintf(".%s", task.ID)
^
cli/command/service/logs.go:217:16: fmt.Sprintf can be replaced with string concatenation (perfsprint)
taskName += fmt.Sprintf(".%s", stringid.TruncateID(task.ID))
^
cli/command/service/progress/progress_test.go:877:18: fmt.Sprintf can be replaced with string concatenation (perfsprint)
ID: fmt.Sprintf("task%s", nodeID),
^
cli/command/stack/swarm/remove.go:61:24: fmt.Sprintf can be replaced with string concatenation (perfsprint)
errs = append(errs, fmt.Sprintf("Failed to remove some resources from stack: %s", namespace))
^
cli/command/swarm/ipnet_slice_test.go:32:9: fmt.Sprintf can be replaced with string concatenation (perfsprint)
arg := fmt.Sprintf("--cidrs=%s", strings.Join(vals, ","))
^
cli/command/swarm/ipnet_slice_test.go:137:30: fmt.Sprintf can be replaced with string concatenation (perfsprint)
if err := f.Parse([]string{fmt.Sprintf("--cidrs=%s", strings.Join(test.FlagArg, ","))}); err != nil {
^
cli/compose/schema/schema.go:105:11: fmt.Sprintf can be replaced with string concatenation (perfsprint)
return fmt.Sprintf("must be a %s", humanReadableType(expectedType))
^
cli/manifest/store/store.go:165:9: fmt.Sprintf can be replaced with string concatenation (perfsprint)
return fmt.Sprintf("No such manifest: %s", n.object)
^
e2e/image/push_test.go:340:4: fmt.Sprintf can be replaced with string concatenation (perfsprint)
fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
^
e2e/image/push_test.go:341:4: fmt.Sprintf can be replaced with string concatenation (perfsprint)
fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
^
e2e/image/push_test.go:342:4: fmt.Sprintf can be replaced with string concatenation (perfsprint)
fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
^
e2e/image/push_test.go:343:4: fmt.Sprintf can be replaced with string concatenation (perfsprint)
fmt.Sprintf("NOTARY_DELEGATION_PASSPHRASE=%s", pwd),
^
e2e/plugin/trust_test.go:23:16: fmt.Sprintf can be replaced with string concatenation (perfsprint)
pluginName := fmt.Sprintf("%s/plugin-content-trust", registryPrefix)
^
e2e/plugin/trust_test.go:53:8: fmt.Sprintf can be replaced with string concatenation (perfsprint)
Out: fmt.Sprintf("Installed plugin %s", pluginName),
^
e2e/trust/revoke_test.go:62:57: fmt.Sprintf can be replaced with string concatenation (perfsprint)
icmd.RunCommand("docker", "tag", fixtures.AlpineImage, fmt.Sprintf("%s:v1", revokeRepo)).Assert(t, icmd.Success)
^
e2e/trust/revoke_test.go:64:49: fmt.Sprintf can be replaced with string concatenation (perfsprint)
icmd.Command("docker", "-D", "trust", "sign", fmt.Sprintf("%s:v1", revokeRepo)),
^
e2e/trust/revoke_test.go:68:58: fmt.Sprintf can be replaced with string concatenation (perfsprint)
icmd.RunCommand("docker", "tag", fixtures.BusyboxImage, fmt.Sprintf("%s:v2", revokeRepo)).Assert(t, icmd.Success)
^
e2e/trust/revoke_test.go:70:49: fmt.Sprintf can be replaced with string concatenation (perfsprint)
icmd.Command("docker", "-D", "trust", "sign", fmt.Sprintf("%s:v2", revokeRepo)),
^
e2e/trust/sign_test.go:36:47: fmt.Sprintf can be replaced with string concatenation (perfsprint)
assert.Check(t, is.Contains(result.Stdout(), fmt.Sprintf("v1: digest: sha256:%s", fixtures.AlpineSha)))
^
e2e/trust/sign_test.go:53:47: fmt.Sprintf can be replaced with string concatenation (perfsprint)
assert.Check(t, is.Contains(result.Stdout(), fmt.Sprintf("v1: digest: sha256:%s", fixtures.BusyboxSha)))
^
e2e/trust/sign_test.go:65:47: fmt.Sprintf can be replaced with string concatenation (perfsprint)
assert.Check(t, is.Contains(result.Stdout(), fmt.Sprintf("v1: digest: sha256:%s", fixtures.AlpineSha)))
^
opts/file.go:21:9: fmt.Sprintf can be replaced with string concatenation (perfsprint)
return fmt.Sprintf("poorly formatted environment: %s", e.msg)
^
opts/hosts_test.go:26:31: fmt.Sprintf can be replaced with string concatenation (perfsprint)
"tcp://host:": fmt.Sprintf("tcp://host:%s", defaultHTTPPort),
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-06-10 15:07:37 -04:00
|
|
|
opts := &flags.ClientOptions{Hosts: []string{"unix://" + socket}}
|
2022-06-06 12:23:53 -04:00
|
|
|
configFile := &configfile.ConfigFile{}
|
|
|
|
apiClient, err := NewAPIClientFromFlags(opts, configFile)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
initializedCh := make(chan bool)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
cli := &DockerCli{client: apiClient, initTimeout: time.Millisecond}
|
2022-11-22 09:11:08 -05:00
|
|
|
err := cli.Initialize(flags.NewClientOptions())
|
|
|
|
assert.Check(t, err)
|
2022-11-04 10:47:14 -04:00
|
|
|
cli.CurrentVersion()
|
2022-06-06 12:23:53 -04:00
|
|
|
close(initializedCh)
|
|
|
|
}()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-timeoutCtx.Done():
|
|
|
|
t.Fatal("timeout waiting for initialization to complete")
|
|
|
|
case <-initializedCh:
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-timeoutCtx.Done():
|
|
|
|
t.Fatal("server never received an init request")
|
|
|
|
case <-receiveReqCh:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-02 08:19:34 -04:00
|
|
|
// The CLI no longer disables/hides experimental CLI features, however, we need
|
|
|
|
// to verify that existing configuration files do not break
|
2017-12-20 09:04:41 -05:00
|
|
|
func TestExperimentalCLI(t *testing.T) {
|
|
|
|
defaultVersion := "v1.55"
|
|
|
|
|
2022-09-29 11:21:51 -04:00
|
|
|
testcases := []struct {
|
2020-10-02 08:19:34 -04:00
|
|
|
doc string
|
|
|
|
configfile string
|
2017-12-20 09:04:41 -05:00
|
|
|
}{
|
|
|
|
{
|
2020-10-02 08:19:34 -04:00
|
|
|
doc: "default",
|
|
|
|
configfile: `{}`,
|
2017-12-20 09:04:41 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
doc: "experimental",
|
|
|
|
configfile: `{
|
|
|
|
"experimental": "enabled"
|
|
|
|
}`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, testcase := range testcases {
|
2019-10-29 09:37:37 -04:00
|
|
|
testcase := testcase
|
2017-12-20 09:04:41 -05:00
|
|
|
t.Run(testcase.doc, func(t *testing.T) {
|
|
|
|
dir := fs.NewDir(t, testcase.doc, fs.WithFile("config.json", testcase.configfile))
|
|
|
|
defer dir.Remove()
|
|
|
|
apiclient := &fakeClient{
|
|
|
|
version: defaultVersion,
|
2019-01-31 12:50:58 -05:00
|
|
|
pingFunc: func() (types.Ping, error) {
|
|
|
|
return types.Ping{Experimental: true, OSType: "linux", APIVersion: defaultVersion}, nil
|
|
|
|
},
|
2017-12-20 09:04:41 -05:00
|
|
|
}
|
|
|
|
|
2024-06-11 10:49:25 -04:00
|
|
|
cli := &DockerCli{client: apiclient, err: streams.NewOut(os.Stderr)}
|
2022-03-04 07:24:28 -05:00
|
|
|
config.SetDir(dir.Path())
|
2017-12-20 09:04:41 -05:00
|
|
|
err := cli.Initialize(flags.NewClientOptions())
|
2018-03-06 14:44:13 -05:00
|
|
|
assert.NilError(t, err)
|
2017-12-20 09:04:41 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-28 08:52:58 -05:00
|
|
|
func TestNewDockerCliAndOperators(t *testing.T) {
|
|
|
|
// Test default operations and also overriding default ones
|
|
|
|
cli, err := NewDockerCli(
|
|
|
|
WithContentTrust(true),
|
|
|
|
)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
// Check streams are initialized
|
|
|
|
assert.Check(t, cli.In() != nil)
|
|
|
|
assert.Check(t, cli.Out() != nil)
|
|
|
|
assert.Check(t, cli.Err() != nil)
|
|
|
|
assert.Equal(t, cli.ContentTrustEnabled(), true)
|
|
|
|
|
|
|
|
// Apply can modify a dockerCli after construction
|
|
|
|
inbuf := bytes.NewBuffer([]byte("input"))
|
|
|
|
outbuf := bytes.NewBuffer(nil)
|
|
|
|
errbuf := bytes.NewBuffer(nil)
|
2019-10-29 07:15:01 -04:00
|
|
|
err = cli.Apply(
|
2022-02-25 08:35:28 -05:00
|
|
|
WithInputStream(io.NopCloser(inbuf)),
|
2019-01-28 08:52:58 -05:00
|
|
|
WithOutputStream(outbuf),
|
|
|
|
WithErrorStream(errbuf),
|
|
|
|
)
|
2019-10-29 07:15:01 -04:00
|
|
|
assert.NilError(t, err)
|
2019-01-28 08:52:58 -05:00
|
|
|
// Check input stream
|
2022-02-25 08:35:28 -05:00
|
|
|
inputStream, err := io.ReadAll(cli.In())
|
2019-01-28 08:52:58 -05:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Equal(t, string(inputStream), "input")
|
|
|
|
// Check output stream
|
|
|
|
fmt.Fprintf(cli.Out(), "output")
|
2022-02-25 08:35:28 -05:00
|
|
|
outputStream, err := io.ReadAll(outbuf)
|
2019-01-28 08:52:58 -05:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Equal(t, string(outputStream), "output")
|
|
|
|
// Check error stream
|
|
|
|
fmt.Fprintf(cli.Err(), "error")
|
2022-02-25 08:35:28 -05:00
|
|
|
errStream, err := io.ReadAll(errbuf)
|
2019-01-28 08:52:58 -05:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Equal(t, string(errStream), "error")
|
|
|
|
}
|
2019-03-07 09:35:11 -05:00
|
|
|
|
|
|
|
func TestInitializeShouldAlwaysCreateTheContextStore(t *testing.T) {
|
|
|
|
cli, err := NewDockerCli()
|
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.NilError(t, cli.Initialize(flags.NewClientOptions(), WithInitializeClient(func(cli *DockerCli) (client.APIClient, error) {
|
|
|
|
return client.NewClientWithOpts()
|
|
|
|
})))
|
|
|
|
assert.Check(t, cli.ContextStore() != nil)
|
|
|
|
}
|
2023-07-20 11:25:36 -04:00
|
|
|
|
|
|
|
func TestHooksEnabled(t *testing.T) {
|
|
|
|
t.Run("disabled by default", func(t *testing.T) {
|
|
|
|
cli, err := NewDockerCli()
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
assert.Check(t, !cli.HooksEnabled())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("enabled in configFile", func(t *testing.T) {
|
|
|
|
configFile := `{
|
|
|
|
"features": {
|
|
|
|
"hooks": "true"
|
|
|
|
}}`
|
|
|
|
dir := fs.NewDir(t, "", fs.WithFile("config.json", configFile))
|
|
|
|
defer dir.Remove()
|
|
|
|
cli, err := NewDockerCli()
|
|
|
|
assert.NilError(t, err)
|
|
|
|
config.SetDir(dir.Path())
|
|
|
|
|
|
|
|
assert.Check(t, cli.HooksEnabled())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("env var overrides configFile", func(t *testing.T) {
|
|
|
|
configFile := `{
|
|
|
|
"features": {
|
|
|
|
"hooks": "true"
|
|
|
|
}}`
|
|
|
|
t.Setenv("DOCKER_CLI_HOOKS", "false")
|
|
|
|
dir := fs.NewDir(t, "", fs.WithFile("config.json", configFile))
|
|
|
|
defer dir.Remove()
|
|
|
|
cli, err := NewDockerCli()
|
|
|
|
assert.NilError(t, err)
|
|
|
|
config.SetDir(dir.Path())
|
|
|
|
|
|
|
|
assert.Check(t, !cli.HooksEnabled())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("legacy env var overrides configFile", func(t *testing.T) {
|
|
|
|
configFile := `{
|
|
|
|
"features": {
|
|
|
|
"hooks": "true"
|
|
|
|
}}`
|
|
|
|
t.Setenv("DOCKER_CLI_HINTS", "false")
|
|
|
|
dir := fs.NewDir(t, "", fs.WithFile("config.json", configFile))
|
|
|
|
defer dir.Remove()
|
|
|
|
cli, err := NewDockerCli()
|
|
|
|
assert.NilError(t, err)
|
|
|
|
config.SetDir(dir.Path())
|
|
|
|
|
|
|
|
assert.Check(t, !cli.HooksEnabled())
|
|
|
|
})
|
|
|
|
}
|