github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/cli/command/context/create_test.go (about) 1 package context 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "testing" 8 9 "github.com/docker/cli/cli/command" 10 "github.com/docker/cli/cli/config/configfile" 11 "github.com/docker/cli/cli/context/docker" 12 "github.com/docker/cli/cli/context/kubernetes" 13 "github.com/docker/cli/cli/context/store" 14 "github.com/docker/cli/internal/test" 15 "gotest.tools/v3/assert" 16 "gotest.tools/v3/env" 17 ) 18 19 func makeFakeCli(t *testing.T, opts ...func(*test.FakeCli)) (*test.FakeCli, func()) { 20 dir, err := ioutil.TempDir("", t.Name()) 21 assert.NilError(t, err) 22 storeConfig := store.NewConfig( 23 func() interface{} { return &command.DockerContext{} }, 24 store.EndpointTypeGetter(docker.DockerEndpoint, func() interface{} { return &docker.EndpointMeta{} }), 25 store.EndpointTypeGetter(kubernetes.KubernetesEndpoint, func() interface{} { return &kubernetes.EndpointMeta{} }), 26 ) 27 store := &command.ContextStoreWithDefault{ 28 Store: store.New(dir, storeConfig), 29 Resolver: func() (*command.DefaultContext, error) { 30 return &command.DefaultContext{ 31 Meta: store.Metadata{ 32 Endpoints: map[string]interface{}{ 33 docker.DockerEndpoint: docker.EndpointMeta{ 34 Host: "unix:///var/run/docker.sock", 35 }, 36 }, 37 Metadata: command.DockerContext{ 38 Description: "", 39 StackOrchestrator: command.OrchestratorSwarm, 40 }, 41 Name: command.DefaultContextName, 42 }, 43 TLS: store.ContextTLSData{}, 44 }, nil 45 }, 46 } 47 cleanup := func() { 48 os.RemoveAll(dir) 49 } 50 result := test.NewFakeCli(nil, opts...) 51 for _, o := range opts { 52 o(result) 53 } 54 result.SetContextStore(store) 55 return result, cleanup 56 } 57 58 func withCliConfig(configFile *configfile.ConfigFile) func(*test.FakeCli) { 59 return func(m *test.FakeCli) { 60 m.SetConfigFile(configFile) 61 } 62 } 63 64 func TestCreateInvalids(t *testing.T) { 65 cli, cleanup := makeFakeCli(t) 66 defer cleanup() 67 assert.NilError(t, cli.ContextStore().CreateOrUpdate(store.Metadata{Name: "existing-context"})) 68 tests := []struct { 69 options CreateOptions 70 expecterErr string 71 }{ 72 { 73 expecterErr: `context name cannot be empty`, 74 }, 75 { 76 options: CreateOptions{ 77 Name: "default", 78 }, 79 expecterErr: `"default" is a reserved context name`, 80 }, 81 { 82 options: CreateOptions{ 83 Name: " ", 84 }, 85 expecterErr: `context name " " is invalid`, 86 }, 87 { 88 options: CreateOptions{ 89 Name: "existing-context", 90 }, 91 expecterErr: `context "existing-context" already exists`, 92 }, 93 { 94 options: CreateOptions{ 95 Name: "invalid-docker-host", 96 Docker: map[string]string{ 97 keyHost: "some///invalid/host", 98 }, 99 }, 100 expecterErr: `unable to parse docker host`, 101 }, 102 { 103 options: CreateOptions{ 104 Name: "invalid-orchestrator", 105 DefaultStackOrchestrator: "invalid", 106 }, 107 expecterErr: `specified orchestrator "invalid" is invalid, please use either kubernetes, swarm or all`, 108 }, 109 { 110 options: CreateOptions{ 111 Name: "orchestrator-kubernetes-no-endpoint", 112 DefaultStackOrchestrator: "kubernetes", 113 Docker: map[string]string{}, 114 }, 115 expecterErr: `cannot specify orchestrator "kubernetes" without configuring a Kubernetes endpoint`, 116 }, 117 { 118 options: CreateOptions{ 119 Name: "orchestrator-all-no-endpoint", 120 DefaultStackOrchestrator: "all", 121 Docker: map[string]string{}, 122 }, 123 expecterErr: `cannot specify orchestrator "all" without configuring a Kubernetes endpoint`, 124 }, 125 } 126 for _, tc := range tests { 127 tc := tc 128 t.Run(tc.options.Name, func(t *testing.T) { 129 err := RunCreate(cli, &tc.options) 130 assert.ErrorContains(t, err, tc.expecterErr) 131 }) 132 } 133 } 134 135 func assertContextCreateLogging(t *testing.T, cli *test.FakeCli, n string) { 136 assert.Equal(t, n+"\n", cli.OutBuffer().String()) 137 assert.Equal(t, fmt.Sprintf("Successfully created context %q\n", n), cli.ErrBuffer().String()) 138 } 139 140 func TestCreateOrchestratorSwarm(t *testing.T) { 141 cli, cleanup := makeFakeCli(t) 142 defer cleanup() 143 144 err := RunCreate(cli, &CreateOptions{ 145 Name: "test", 146 DefaultStackOrchestrator: "swarm", 147 Docker: map[string]string{}, 148 }) 149 assert.NilError(t, err) 150 assertContextCreateLogging(t, cli, "test") 151 } 152 153 func TestCreateOrchestratorEmpty(t *testing.T) { 154 cli, cleanup := makeFakeCli(t) 155 defer cleanup() 156 157 err := RunCreate(cli, &CreateOptions{ 158 Name: "test", 159 Docker: map[string]string{}, 160 }) 161 assert.NilError(t, err) 162 assertContextCreateLogging(t, cli, "test") 163 } 164 165 func validateTestKubeEndpoint(t *testing.T, s store.Reader, name string) { 166 t.Helper() 167 ctxMetadata, err := s.GetMetadata(name) 168 assert.NilError(t, err) 169 kubeMeta := ctxMetadata.Endpoints[kubernetes.KubernetesEndpoint].(kubernetes.EndpointMeta) 170 kubeEP, err := kubeMeta.WithTLSData(s, name) 171 assert.NilError(t, err) 172 assert.Equal(t, "https://someserver", kubeEP.Host) 173 assert.Equal(t, "the-ca", string(kubeEP.TLSData.CA)) 174 assert.Equal(t, "the-cert", string(kubeEP.TLSData.Cert)) 175 assert.Equal(t, "the-key", string(kubeEP.TLSData.Key)) 176 } 177 178 func createTestContextWithKube(t *testing.T, cli command.Cli) { 179 t.Helper() 180 revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig") 181 defer revert() 182 183 err := RunCreate(cli, &CreateOptions{ 184 Name: "test", 185 DefaultStackOrchestrator: "all", 186 Kubernetes: map[string]string{ 187 keyFrom: "default", 188 }, 189 Docker: map[string]string{}, 190 }) 191 assert.NilError(t, err) 192 } 193 194 func TestCreateOrchestratorAllKubernetesEndpointFromCurrent(t *testing.T) { 195 cli, cleanup := makeFakeCli(t) 196 defer cleanup() 197 createTestContextWithKube(t, cli) 198 assertContextCreateLogging(t, cli, "test") 199 validateTestKubeEndpoint(t, cli.ContextStore(), "test") 200 } 201 202 func TestCreateFromContext(t *testing.T) { 203 cases := []struct { 204 name string 205 description string 206 orchestrator string 207 expectedDescription string 208 docker map[string]string 209 kubernetes map[string]string 210 expectedOrchestrator command.Orchestrator 211 }{ 212 { 213 name: "no-override", 214 expectedDescription: "original description", 215 expectedOrchestrator: command.OrchestratorSwarm, 216 }, 217 { 218 name: "override-description", 219 description: "new description", 220 expectedDescription: "new description", 221 expectedOrchestrator: command.OrchestratorSwarm, 222 }, 223 { 224 name: "override-orchestrator", 225 orchestrator: "kubernetes", 226 expectedDescription: "original description", 227 expectedOrchestrator: command.OrchestratorKubernetes, 228 }, 229 } 230 231 cli, cleanup := makeFakeCli(t) 232 defer cleanup() 233 revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig") 234 defer revert() 235 cli.ResetOutputBuffers() 236 assert.NilError(t, RunCreate(cli, &CreateOptions{ 237 Name: "original", 238 Description: "original description", 239 Docker: map[string]string{ 240 keyHost: "tcp://42.42.42.42:2375", 241 }, 242 Kubernetes: map[string]string{ 243 keyFrom: "default", 244 }, 245 DefaultStackOrchestrator: "swarm", 246 })) 247 assertContextCreateLogging(t, cli, "original") 248 249 cli.ResetOutputBuffers() 250 assert.NilError(t, RunCreate(cli, &CreateOptions{ 251 Name: "dummy", 252 Description: "dummy description", 253 Docker: map[string]string{ 254 keyHost: "tcp://24.24.24.24:2375", 255 }, 256 Kubernetes: map[string]string{ 257 keyFrom: "default", 258 }, 259 DefaultStackOrchestrator: "swarm", 260 })) 261 assertContextCreateLogging(t, cli, "dummy") 262 263 cli.SetCurrentContext("dummy") 264 265 for _, c := range cases { 266 c := c 267 t.Run(c.name, func(t *testing.T) { 268 cli.ResetOutputBuffers() 269 err := RunCreate(cli, &CreateOptions{ 270 From: "original", 271 Name: c.name, 272 Description: c.description, 273 DefaultStackOrchestrator: c.orchestrator, 274 Docker: c.docker, 275 Kubernetes: c.kubernetes, 276 }) 277 assert.NilError(t, err) 278 assertContextCreateLogging(t, cli, c.name) 279 newContext, err := cli.ContextStore().GetMetadata(c.name) 280 assert.NilError(t, err) 281 newContextTyped, err := command.GetDockerContext(newContext) 282 assert.NilError(t, err) 283 dockerEndpoint, err := docker.EndpointFromContext(newContext) 284 assert.NilError(t, err) 285 kubeEndpoint := kubernetes.EndpointFromContext(newContext) 286 assert.Check(t, kubeEndpoint != nil) 287 assert.Equal(t, newContextTyped.Description, c.expectedDescription) 288 assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator) 289 assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375") 290 assert.Equal(t, kubeEndpoint.Host, "https://someserver") 291 }) 292 } 293 } 294 295 func TestCreateFromCurrent(t *testing.T) { 296 cases := []struct { 297 name string 298 description string 299 orchestrator string 300 expectedDescription string 301 expectedOrchestrator command.Orchestrator 302 }{ 303 { 304 name: "no-override", 305 expectedDescription: "original description", 306 expectedOrchestrator: command.OrchestratorSwarm, 307 }, 308 { 309 name: "override-description", 310 description: "new description", 311 expectedDescription: "new description", 312 expectedOrchestrator: command.OrchestratorSwarm, 313 }, 314 { 315 name: "override-orchestrator", 316 orchestrator: "kubernetes", 317 expectedDescription: "original description", 318 expectedOrchestrator: command.OrchestratorKubernetes, 319 }, 320 } 321 322 cli, cleanup := makeFakeCli(t) 323 defer cleanup() 324 revert := env.Patch(t, "KUBECONFIG", "./testdata/test-kubeconfig") 325 defer revert() 326 cli.ResetOutputBuffers() 327 assert.NilError(t, RunCreate(cli, &CreateOptions{ 328 Name: "original", 329 Description: "original description", 330 Docker: map[string]string{ 331 keyHost: "tcp://42.42.42.42:2375", 332 }, 333 Kubernetes: map[string]string{ 334 keyFrom: "default", 335 }, 336 DefaultStackOrchestrator: "swarm", 337 })) 338 assertContextCreateLogging(t, cli, "original") 339 340 cli.SetCurrentContext("original") 341 342 for _, c := range cases { 343 c := c 344 t.Run(c.name, func(t *testing.T) { 345 cli.ResetOutputBuffers() 346 err := RunCreate(cli, &CreateOptions{ 347 Name: c.name, 348 Description: c.description, 349 DefaultStackOrchestrator: c.orchestrator, 350 }) 351 assert.NilError(t, err) 352 assertContextCreateLogging(t, cli, c.name) 353 newContext, err := cli.ContextStore().GetMetadata(c.name) 354 assert.NilError(t, err) 355 newContextTyped, err := command.GetDockerContext(newContext) 356 assert.NilError(t, err) 357 dockerEndpoint, err := docker.EndpointFromContext(newContext) 358 assert.NilError(t, err) 359 kubeEndpoint := kubernetes.EndpointFromContext(newContext) 360 assert.Check(t, kubeEndpoint != nil) 361 assert.Equal(t, newContextTyped.Description, c.expectedDescription) 362 assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator) 363 assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375") 364 assert.Equal(t, kubeEndpoint.Host, "https://someserver") 365 }) 366 } 367 }