DockerCLI/cli/command/context/create_test.go

357 lines
10 KiB
Go

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/kubernetes"
"github.com/docker/cli/cli/context/store"
"github.com/docker/cli/internal/test"
"gotest.tools/v3/assert"
"gotest.tools/v3/env"
)
func makeFakeCli(t *testing.T, opts ...func(*test.FakeCli)) *test.FakeCli {
t.Helper()
dir := t.TempDir()
storeConfig := store.NewConfig(
func() interface{} { return &command.DockerContext{} },
store.EndpointTypeGetter(docker.DockerEndpoint, func() interface{} { return &docker.EndpointMeta{} }),
store.EndpointTypeGetter(kubernetes.KubernetesEndpoint, func() interface{} { return &kubernetes.EndpointMeta{} }),
)
store := &command.ContextStoreWithDefault{
Store: store.New(dir, storeConfig),
Resolver: func() (*command.DefaultContext, error) {
return &command.DefaultContext{
Meta: store.Metadata{
Endpoints: map[string]interface{}{
docker.DockerEndpoint: docker.EndpointMeta{
Host: "unix:///var/run/docker.sock",
},
},
Metadata: command.DockerContext{
Description: "",
StackOrchestrator: command.OrchestratorSwarm,
},
Name: command.DefaultContextName,
},
TLS: store.ContextTLSData{},
}, nil
},
}
result := test.NewFakeCli(nil, opts...)
for _, o := range opts {
o(result)
}
result.SetContextStore(store)
return result
}
func withCliConfig(configFile *configfile.ConfigFile) func(*test.FakeCli) {
return func(m *test.FakeCli) {
m.SetConfigFile(configFile)
}
}
func TestCreateInvalids(t *testing.T) {
cli := makeFakeCli(t)
assert.NilError(t, cli.ContextStore().CreateOrUpdate(store.Metadata{Name: "existing-context"}))
tests := []struct {
options CreateOptions
expecterErr string
}{
{
expecterErr: `context name cannot be empty`,
},
{
options: CreateOptions{
Name: "default",
},
expecterErr: `"default" is a reserved context name`,
},
{
options: CreateOptions{
Name: " ",
},
expecterErr: `context name " " is invalid`,
},
{
options: CreateOptions{
Name: "existing-context",
},
expecterErr: `context "existing-context" already exists`,
},
{
options: CreateOptions{
Name: "invalid-docker-host",
Docker: map[string]string{
keyHost: "some///invalid/host",
},
},
expecterErr: `unable to parse docker host`,
},
{
options: CreateOptions{
Name: "invalid-orchestrator",
DefaultStackOrchestrator: "invalid",
},
expecterErr: `specified orchestrator "invalid" is invalid, please use either kubernetes, swarm or all`,
},
{
options: CreateOptions{
Name: "orchestrator-kubernetes-no-endpoint",
DefaultStackOrchestrator: "kubernetes",
Docker: map[string]string{},
},
expecterErr: `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`,
},
{
options: CreateOptions{
Name: "orchestrator-all-no-endpoint",
DefaultStackOrchestrator: "all",
Docker: map[string]string{},
},
expecterErr: `cannot specify orchestrator "all" without configuring a Kubernetes endpoint`,
},
}
for _, tc := range tests {
tc := tc
t.Run(tc.options.Name, func(t *testing.T) {
err := RunCreate(cli, &tc.options)
assert.ErrorContains(t, err, tc.expecterErr)
})
}
}
func assertContextCreateLogging(t *testing.T, cli *test.FakeCli, n string) {
assert.Equal(t, n+"\n", cli.OutBuffer().String())
assert.Equal(t, fmt.Sprintf("Successfully created context %q\n", n), cli.ErrBuffer().String())
}
func TestCreateOrchestratorSwarm(t *testing.T) {
cli := makeFakeCli(t)
err := RunCreate(cli, &CreateOptions{
Name: "test",
DefaultStackOrchestrator: "swarm",
Docker: map[string]string{},
})
assert.NilError(t, err)
assertContextCreateLogging(t, cli, "test")
}
func TestCreateOrchestratorEmpty(t *testing.T) {
cli := makeFakeCli(t)
err := RunCreate(cli, &CreateOptions{
Name: "test",
Docker: map[string]string{},
})
assert.NilError(t, err)
assertContextCreateLogging(t, cli, "test")
}
func validateTestKubeEndpoint(t *testing.T, s store.Reader, name string) {
t.Helper()
ctxMetadata, err := s.GetMetadata(name)
assert.NilError(t, err)
kubeMeta := ctxMetadata.Endpoints[kubernetes.KubernetesEndpoint].(kubernetes.EndpointMeta)
kubeEP, err := kubeMeta.WithTLSData(s, name)
assert.NilError(t, err)
assert.Equal(t, "https://someserver.example.com", kubeEP.Host)
assert.Equal(t, "the-ca", string(kubeEP.TLSData.CA))
assert.Equal(t, "the-cert", string(kubeEP.TLSData.Cert))
assert.Equal(t, "the-key", string(kubeEP.TLSData.Key))
}
func createTestContextWithKube(t *testing.T, cli command.Cli) {
t.Helper()
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
defer revert()
err := RunCreate(cli, &CreateOptions{
Name: "test",
DefaultStackOrchestrator: "all",
Kubernetes: map[string]string{
keyFrom: "default",
},
Docker: map[string]string{},
})
assert.NilError(t, err)
}
func TestCreateOrchestratorAllKubernetesEndpointFromCurrent(t *testing.T) {
cli := makeFakeCli(t)
createTestContextWithKube(t, cli)
assertContextCreateLogging(t, cli, "test")
validateTestKubeEndpoint(t, cli.ContextStore(), "test")
}
func TestCreateFromContext(t *testing.T) {
cases := []struct {
name string
description string
orchestrator string
expectedDescription string
docker map[string]string
kubernetes map[string]string
expectedOrchestrator command.Orchestrator
}{
{
name: "no-override",
expectedDescription: "original description",
expectedOrchestrator: command.OrchestratorSwarm,
},
{
name: "override-description",
description: "new description",
expectedDescription: "new description",
expectedOrchestrator: command.OrchestratorSwarm,
},
{
name: "override-orchestrator",
orchestrator: "kubernetes",
expectedDescription: "original description",
expectedOrchestrator: command.OrchestratorKubernetes,
},
}
cli := makeFakeCli(t)
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
defer revert()
cli.ResetOutputBuffers()
assert.NilError(t, RunCreate(cli, &CreateOptions{
Name: "original",
Description: "original description",
Docker: map[string]string{
keyHost: "tcp://42.42.42.42:2375",
},
Kubernetes: map[string]string{
keyFrom: "default",
},
DefaultStackOrchestrator: "swarm",
}))
assertContextCreateLogging(t, cli, "original")
cli.ResetOutputBuffers()
assert.NilError(t, RunCreate(cli, &CreateOptions{
Name: "dummy",
Description: "dummy description",
Docker: map[string]string{
keyHost: "tcp://24.24.24.24:2375",
},
Kubernetes: map[string]string{
keyFrom: "default",
},
DefaultStackOrchestrator: "swarm",
}))
assertContextCreateLogging(t, cli, "dummy")
cli.SetCurrentContext("dummy")
for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
cli.ResetOutputBuffers()
err := RunCreate(cli, &CreateOptions{
From: "original",
Name: c.name,
Description: c.description,
DefaultStackOrchestrator: c.orchestrator,
Docker: c.docker,
Kubernetes: c.kubernetes,
})
assert.NilError(t, err)
assertContextCreateLogging(t, cli, c.name)
newContext, err := cli.ContextStore().GetMetadata(c.name)
assert.NilError(t, err)
newContextTyped, err := command.GetDockerContext(newContext)
assert.NilError(t, err)
dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err)
kubeEndpoint := kubernetes.EndpointFromContext(newContext)
assert.Check(t, kubeEndpoint != nil)
assert.Equal(t, newContextTyped.Description, c.expectedDescription)
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
assert.Equal(t, kubeEndpoint.Host, "https://someserver.example.com")
})
}
}
func TestCreateFromCurrent(t *testing.T) {
cases := []struct {
name string
description string
orchestrator string
expectedDescription string
expectedOrchestrator command.Orchestrator
}{
{
name: "no-override",
expectedDescription: "original description",
expectedOrchestrator: command.OrchestratorSwarm,
},
{
name: "override-description",
description: "new description",
expectedDescription: "new description",
expectedOrchestrator: command.OrchestratorSwarm,
},
{
name: "override-orchestrator",
orchestrator: "kubernetes",
expectedDescription: "original description",
expectedOrchestrator: command.OrchestratorKubernetes,
},
}
cli := makeFakeCli(t)
revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig")
defer revert()
cli.ResetOutputBuffers()
assert.NilError(t, RunCreate(cli, &CreateOptions{
Name: "original",
Description: "original description",
Docker: map[string]string{
keyHost: "tcp://42.42.42.42:2375",
},
Kubernetes: map[string]string{
keyFrom: "default",
},
DefaultStackOrchestrator: "swarm",
}))
assertContextCreateLogging(t, cli, "original")
cli.SetCurrentContext("original")
for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
cli.ResetOutputBuffers()
err := RunCreate(cli, &CreateOptions{
Name: c.name,
Description: c.description,
DefaultStackOrchestrator: c.orchestrator,
})
assert.NilError(t, err)
assertContextCreateLogging(t, cli, c.name)
newContext, err := cli.ContextStore().GetMetadata(c.name)
assert.NilError(t, err)
newContextTyped, err := command.GetDockerContext(newContext)
assert.NilError(t, err)
dockerEndpoint, err := docker.EndpointFromContext(newContext)
assert.NilError(t, err)
kubeEndpoint := kubernetes.EndpointFromContext(newContext)
assert.Check(t, kubeEndpoint != nil)
assert.Equal(t, newContextTyped.Description, c.expectedDescription)
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
assert.Equal(t, kubeEndpoint.Host, "https://someserver.example.com")
})
}
}