Files
docker-cli/cli/command/context/create_test.go
Sebastiaan van Stijn 95eeafa551 cli/command/context: deprecate exported types and functions
These functions and types are shallow wrappers around the context
store and were intended for internal use as implementation for the
CLI itself.

They were exported in 3126920af1 to be
used by plugins and Docker Desktop. However, there's currently no public
uses of this, and Docker Desktop does not use these functions.

This patch deprecates the exported functions as they were meant to be
implementation specific for the CLI. If there's a need to provide
utilities for manipulating the context-store other than through the
CLI itself, we can consider creating an SDK for that purpose.

This deprecates:

- `RunCreate` and `CreateOptions`
- `RunExport` and `ExportOptions`
- `RunImport`
- `RunRemove` and `RemoveOptions`
- `RunUpdate` and `UpdateOptions`
- `RunUse`

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-08-30 01:51:12 +02:00

285 lines
7.3 KiB
Go

// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.23
package context
import (
"fmt"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
"github.com/docker/cli/internal/test"
"gotest.tools/v3/assert"
)
func makeFakeCli(t *testing.T, opts ...func(*test.FakeCli)) *test.FakeCli {
t.Helper()
dir := t.TempDir()
storeConfig := store.NewConfig(
func() any { return &command.DockerContext{} },
store.EndpointTypeGetter(docker.DockerEndpoint, func() any { return &docker.EndpointMeta{} }),
)
contextStore := &command.ContextStoreWithDefault{
Store: store.New(dir, storeConfig),
Resolver: func() (*command.DefaultContext, error) {
return &command.DefaultContext{
Meta: store.Metadata{
Endpoints: map[string]any{
docker.DockerEndpoint: docker.EndpointMeta{
Host: "unix:///var/run/docker.sock",
},
},
Metadata: command.DockerContext{
Description: "",
},
Name: command.DefaultContextName,
},
TLS: store.ContextTLSData{},
}, nil
},
}
result := test.NewFakeCli(nil, opts...)
for _, o := range opts {
o(result)
}
result.SetContextStore(contextStore)
return result
}
func withCliConfig(configFile *configfile.ConfigFile) func(*test.FakeCli) {
return func(m *test.FakeCli) {
m.SetConfigFile(configFile)
}
}
func TestCreate(t *testing.T) {
cli := makeFakeCli(t)
assert.NilError(t, cli.ContextStore().CreateOrUpdate(store.Metadata{Name: "existing-context"}))
tests := []struct {
doc string
options createOptions
expecterErr string
}{
{
doc: "empty name",
expecterErr: `context name cannot be empty`,
},
{
doc: "reserved name",
options: createOptions{
name: "default",
},
expecterErr: `"default" is a reserved context name`,
},
{
doc: "whitespace-only name",
options: createOptions{
name: " ",
},
expecterErr: `context name " " is invalid`,
},
{
doc: "existing context",
options: createOptions{
name: "existing-context",
},
expecterErr: `context "existing-context" already exists`,
},
{
doc: "invalid docker host",
options: createOptions{
name: "invalid-docker-host",
endpoint: map[string]string{
"host": "some///invalid/host",
},
},
expecterErr: `unable to parse docker host`,
},
{
doc: "ssh host with skip-tls-verify=false",
options: createOptions{
name: "skip-tls-verify-false",
endpoint: map[string]string{
"host": "ssh://example.com,skip-tls-verify=false",
},
},
},
{
doc: "ssh host with skip-tls-verify=true",
options: createOptions{
name: "skip-tls-verify-true",
endpoint: map[string]string{
"host": "ssh://example.com,skip-tls-verify=true",
},
},
},
{
doc: "ssh host with skip-tls-verify=INVALID",
options: createOptions{
name: "skip-tls-verify-invalid",
endpoint: map[string]string{
"host": "ssh://example.com",
"skip-tls-verify": "INVALID",
},
},
expecterErr: `unable to create docker endpoint config: skip-tls-verify: parsing "INVALID": invalid syntax`,
},
{
doc: "unknown option",
options: createOptions{
name: "unknown-option",
endpoint: map[string]string{
"UNKNOWN": "value",
},
},
expecterErr: `unable to create docker endpoint config: unrecognized config key: UNKNOWN`,
},
}
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
err := runCreate(cli, &tc.options)
if tc.expecterErr == "" {
assert.NilError(t, err)
} else {
assert.ErrorContains(t, err, tc.expecterErr)
}
})
}
}
func assertContextCreateLogging(t *testing.T, cli *test.FakeCli, n string) {
t.Helper()
assert.Equal(t, n+"\n", cli.OutBuffer().String())
assert.Equal(t, fmt.Sprintf("Successfully created context %q\n", n), cli.ErrBuffer().String())
}
func TestCreateOrchestratorEmpty(t *testing.T) {
cli := makeFakeCli(t)
err := runCreate(cli, &createOptions{
name: "test",
endpoint: map[string]string{},
})
assert.NilError(t, err)
assertContextCreateLogging(t, cli, "test")
}
func TestCreateFromContext(t *testing.T) {
cases := []struct {
name string
description string
expectedDescription string
docker map[string]string
}{
{
name: "no-override",
expectedDescription: "original description",
},
{
name: "override-description",
description: "new description",
expectedDescription: "new description",
},
}
cli := makeFakeCli(t)
cli.ResetOutputBuffers()
assert.NilError(t, runCreate(cli, &createOptions{
name: "original",
description: "original description",
endpoint: map[string]string{
keyHost: "tcp://42.42.42.42:2375",
},
}))
assertContextCreateLogging(t, cli, "original")
cli.ResetOutputBuffers()
assert.NilError(t, runCreate(cli, &createOptions{
name: "dummy",
description: "dummy description",
endpoint: map[string]string{
keyHost: "tcp://24.24.24.24:2375",
},
}))
assertContextCreateLogging(t, cli, "dummy")
cli.SetCurrentContext("dummy")
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
cli.ResetOutputBuffers()
err := runCreate(cli, &createOptions{
from: "original",
name: tc.name,
description: tc.description,
endpoint: tc.docker,
})
assert.NilError(t, err)
assertContextCreateLogging(t, cli, tc.name)
newContext, err := cli.ContextStore().GetMetadata(tc.name)
assert.NilError(t, err)
newContextTyped, err := command.GetDockerContext(newContext)
assert.NilError(t, err)
dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err)
assert.Equal(t, newContextTyped.Description, tc.expectedDescription)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
})
}
}
func TestCreateFromCurrent(t *testing.T) {
cases := []struct {
name string
description string
orchestrator string
expectedDescription string
}{
{
name: "no-override",
expectedDescription: "original description",
},
{
name: "override-description",
description: "new description",
expectedDescription: "new description",
},
}
cli := makeFakeCli(t)
cli.ResetOutputBuffers()
assert.NilError(t, runCreate(cli, &createOptions{
name: "original",
description: "original description",
endpoint: map[string]string{
keyHost: "tcp://42.42.42.42:2375",
},
}))
assertContextCreateLogging(t, cli, "original")
cli.SetCurrentContext("original")
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
cli.ResetOutputBuffers()
err := runCreate(cli, &createOptions{
name: tc.name,
description: tc.description,
})
assert.NilError(t, err)
assertContextCreateLogging(t, cli, tc.name)
newContext, err := cli.ContextStore().GetMetadata(tc.name)
assert.NilError(t, err)
newContextTyped, err := command.GetDockerContext(newContext)
assert.NilError(t, err)
dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err)
assert.Equal(t, newContextTyped.Description, tc.expectedDescription)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
})
}
}