gopkg.in/openshift/source-to-image.v1@v1.2.0/pkg/docker/docker_test.go (about) 1 package docker 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "reflect" 10 "strings" 11 "testing" 12 13 "github.com/openshift/source-to-image/pkg/api/constants" 14 dockertest "github.com/openshift/source-to-image/pkg/docker/test" 15 "github.com/openshift/source-to-image/pkg/errors" 16 testfs "github.com/openshift/source-to-image/pkg/test/fs" 17 18 dockertypes "github.com/docker/docker/api/types" 19 dockercontainer "github.com/docker/docker/api/types/container" 20 dockerstrslice "github.com/docker/docker/api/types/strslice" 21 ) 22 23 func TestContainerName(t *testing.T) { 24 got := containerName("sub.domain.com:5000/repo:tag@sha256:ffffff") 25 want := "s2i_sub_domain_com_5000_repo_tag_sha256_ffffff" 26 if !strings.Contains(got, want) { 27 t.Errorf("want %v is not substring of got %v", want, got) 28 } 29 } 30 31 func getDocker(client Client) *stiDocker { 32 return &stiDocker{ 33 client: client, 34 pullAuth: dockertypes.AuthConfig{}, 35 } 36 } 37 38 func TestRemoveContainer(t *testing.T) { 39 fakeDocker := dockertest.NewFakeDockerClient() 40 dh := getDocker(fakeDocker) 41 containerID := "testContainerId" 42 fakeDocker.Containers[containerID] = dockercontainer.Config{} 43 err := dh.RemoveContainer(containerID) 44 if err != nil { 45 t.Errorf("%+v", err) 46 } 47 expectedCalls := []string{"remove"} 48 if !reflect.DeepEqual(fakeDocker.Calls, expectedCalls) { 49 t.Errorf("Expected fakeDocker.Calls %v, got %v", expectedCalls, fakeDocker.Calls) 50 } 51 } 52 53 func TestCommitContainer(t *testing.T) { 54 type commitTest struct { 55 containerID string 56 containerTag string 57 expectedImageID string 58 expectedError error 59 } 60 61 tests := map[string]commitTest{ 62 "valid": { 63 containerID: "test-container-id", 64 containerTag: "test-container-tag", 65 expectedImageID: "test-container-tag", 66 }, 67 "error": { 68 containerID: "test-container-id", 69 containerTag: "test-container-tag", 70 expectedImageID: "test-container-tag", 71 expectedError: fmt.Errorf("Test error"), 72 }, 73 } 74 75 for desc, tst := range tests { 76 opt := CommitContainerOptions{ 77 ContainerID: tst.containerID, 78 Repository: tst.containerTag, 79 } 80 param := dockertypes.ContainerCommitOptions{ 81 Reference: tst.containerTag, 82 } 83 resp := dockertypes.IDResponse{ 84 ID: tst.expectedImageID, 85 } 86 fakeDocker := &dockertest.FakeDockerClient{ 87 ContainerCommitResponse: resp, 88 ContainerCommitErr: tst.expectedError, 89 } 90 dh := getDocker(fakeDocker) 91 92 imageID, err := dh.CommitContainer(opt) 93 if err != tst.expectedError { 94 t.Errorf("test case %s: Unexpected error returned: %v", desc, err) 95 } 96 if tst.containerID != fakeDocker.ContainerCommitID { 97 t.Errorf("test case %s: Commit container called with unexpected container id: %s and %+v", desc, tst.containerID, fakeDocker.ContainerCommitID) 98 } 99 if !reflect.DeepEqual(param, fakeDocker.ContainerCommitOptions) { 100 t.Errorf("test case %s: Commit container called with unexpected parameters: %+v and %+v", desc, param, fakeDocker.ContainerCommitOptions) 101 } 102 if tst.expectedError == nil && imageID != tst.expectedImageID { 103 t.Errorf("test case %s: Did not return the correct image id: %s", desc, imageID) 104 } 105 } 106 } 107 108 func TestCopyToContainer(t *testing.T) { 109 type copyToTest struct { 110 containerID string 111 src string 112 destPath string 113 } 114 115 tests := map[string]copyToTest{ 116 "valid": { 117 containerID: "test-container-id", 118 src: "foo", 119 }, 120 "error": { 121 containerID: "test-container-id", 122 src: "badsource", 123 }, 124 } 125 126 for desc, tst := range tests { 127 var tempDir, fileName string 128 var err error 129 var file *os.File 130 if len(tst.src) > 0 { 131 tempDir, err = ioutil.TempDir("", tst.src) 132 defer os.RemoveAll(tempDir) 133 fileName = filepath.Join(tempDir, "bar") 134 if err = os.MkdirAll(filepath.Dir(fileName), 0700); err == nil { 135 file, err = os.Create(fileName) 136 if err == nil { 137 defer file.Close() 138 file.WriteString("asdf") 139 } 140 } 141 } 142 if err != nil { 143 t.Fatalf("Error creating src test files: %v", err) 144 } 145 fakeDocker := &dockertest.FakeDockerClient{ 146 CopyToContainerContent: file, 147 } 148 dh := getDocker(fakeDocker) 149 150 err = dh.UploadToContainer(&testfs.FakeFileSystem{}, fileName, fileName, tst.containerID) 151 // the error we are inducing will prevent call into engine-api 152 if len(tst.src) > 0 { 153 if err != nil { 154 t.Errorf("test case %s: Unexpected error returned: %v", desc, err) 155 } 156 if tst.containerID != fakeDocker.CopyToContainerID { 157 t.Errorf("test case %s: copy to container called with unexpected id: %s and %s", desc, tst.containerID, fakeDocker.CopyToContainerID) 158 } 159 } else { 160 if err == nil { 161 t.Errorf("test case %s: Unexpected error returned: %v", desc, err) 162 } 163 if len(fakeDocker.CopyToContainerID) > 0 { 164 t.Errorf("test case %s: copy to container called with unexpected id: %s and %s", desc, tst.containerID, fakeDocker.CopyToContainerID) 165 } 166 } 167 // the directory of our file gets passed down to the engine-api method 168 if tempDir != fakeDocker.CopyToContainerPath { 169 t.Errorf("test case %s: copy to container called with unexpected path: %s and %s", desc, tempDir, fakeDocker.CopyToContainerPath) 170 } 171 // reflect.DeepEqual does not help here cause the reader is transformed prior to calling the engine-api stack, so just make sure it is no nil 172 if file != nil && fakeDocker.CopyToContainerContent == nil { 173 t.Errorf("test case %s: copy to container content was not passed through", desc) 174 } 175 } 176 } 177 178 func TestCopyFromContainer(t *testing.T) { 179 type copyFromTest struct { 180 containerID string 181 srcPath string 182 expectedError error 183 } 184 185 tests := map[string]copyFromTest{ 186 "valid": { 187 containerID: "test-container-id", 188 srcPath: "/foo/bar", 189 }, 190 "error": { 191 containerID: "test-container-id", 192 srcPath: "/foo/bar", 193 expectedError: fmt.Errorf("Test error"), 194 }, 195 } 196 197 for desc, tst := range tests { 198 buffer := bytes.NewBuffer([]byte("")) 199 fakeDocker := &dockertest.FakeDockerClient{ 200 CopyFromContainerErr: tst.expectedError, 201 } 202 dh := getDocker(fakeDocker) 203 204 err := dh.DownloadFromContainer(tst.srcPath, buffer, tst.containerID) 205 if err != tst.expectedError { 206 t.Errorf("test case %s: Unexpected error returned: %v", desc, err) 207 } 208 if fakeDocker.CopyFromContainerID != tst.containerID { 209 t.Errorf("test case %s: Unexpected container id: %s and %s", desc, tst.containerID, fakeDocker.CopyFromContainerID) 210 } 211 if fakeDocker.CopyFromContainerPath != tst.srcPath { 212 t.Errorf("test case %s: Unexpected container id: %s and %s", desc, tst.srcPath, fakeDocker.CopyFromContainerPath) 213 } 214 } 215 } 216 217 func TestImageBuild(t *testing.T) { 218 type waitTest struct { 219 imageID string 220 expectedError error 221 } 222 223 tests := map[string]waitTest{ 224 "valid": { 225 imageID: "test-container-id", 226 }, 227 "error": { 228 imageID: "test-container-id", 229 expectedError: fmt.Errorf("Test error"), 230 }, 231 } 232 233 for desc, tst := range tests { 234 fakeDocker := &dockertest.FakeDockerClient{ 235 BuildImageErr: tst.expectedError, 236 } 237 dh := getDocker(fakeDocker) 238 opts := BuildImageOptions{ 239 Name: tst.imageID, 240 } 241 242 err := dh.BuildImage(opts) 243 if err != tst.expectedError { 244 t.Errorf("test case %s: Unexpected error returned: %v", desc, err) 245 } 246 if len(fakeDocker.BuildImageOpts.Tags) != 1 || fakeDocker.BuildImageOpts.Tags[0] != tst.imageID { 247 t.Errorf("test case %s: Unexpected container id: %s and %+v", desc, tst.imageID, fakeDocker.BuildImageOpts.Tags) 248 } 249 } 250 } 251 252 func TestGetScriptsURL(t *testing.T) { 253 type urltest struct { 254 image dockertypes.ImageInspect 255 result string 256 calls []string 257 inspectErr error 258 } 259 tests := map[string]urltest{ 260 "not present": { 261 calls: []string{"inspect_image"}, 262 image: dockertypes.ImageInspect{ 263 ContainerConfig: &dockercontainer.Config{ 264 Env: []string{"Env1=value1"}, 265 Labels: map[string]string{}, 266 }, 267 Config: &dockercontainer.Config{ 268 Env: []string{"Env2=value2"}, 269 Labels: map[string]string{}, 270 }, 271 }, 272 result: "", 273 }, 274 275 "env in containerConfig": { 276 calls: []string{"inspect_image"}, 277 image: dockertypes.ImageInspect{ 278 ContainerConfig: &dockercontainer.Config{ 279 Env: []string{"Env1=value1", constants.ScriptsURLEnvironment + "=test_url_value"}, 280 }, 281 Config: &dockercontainer.Config{}, 282 }, 283 result: "", 284 }, 285 286 "env in image config": { 287 calls: []string{"inspect_image"}, 288 image: dockertypes.ImageInspect{ 289 ContainerConfig: &dockercontainer.Config{}, 290 Config: &dockercontainer.Config{ 291 Env: []string{ 292 "Env1=value1", 293 constants.ScriptsURLEnvironment + "=test_url_value_2", 294 "Env2=value2", 295 }, 296 }, 297 }, 298 result: "test_url_value_2", 299 }, 300 301 "label in containerConfig": { 302 calls: []string{"inspect_image"}, 303 image: dockertypes.ImageInspect{ 304 ContainerConfig: &dockercontainer.Config{ 305 Labels: map[string]string{constants.ScriptsURLLabel: "test_url_value"}, 306 }, 307 Config: &dockercontainer.Config{}, 308 }, 309 result: "", 310 }, 311 312 "label in image config": { 313 calls: []string{"inspect_image"}, 314 image: dockertypes.ImageInspect{ 315 ContainerConfig: &dockercontainer.Config{}, 316 Config: &dockercontainer.Config{ 317 Labels: map[string]string{constants.ScriptsURLLabel: "test_url_value_2"}, 318 }, 319 }, 320 result: "test_url_value_2", 321 }, 322 323 "inspect error": { 324 calls: []string{"inspect_image", "pull"}, 325 image: dockertypes.ImageInspect{}, 326 inspectErr: fmt.Errorf("Inspect error"), 327 }, 328 } 329 for desc, tst := range tests { 330 fakeDocker := dockertest.NewFakeDockerClient() 331 dh := getDocker(fakeDocker) 332 tst.image.ID = "test/image:latest" 333 if tst.inspectErr != nil { 334 fakeDocker.PullFail = tst.inspectErr 335 } else { 336 fakeDocker.Images = map[string]dockertypes.ImageInspect{tst.image.ID: tst.image} 337 } 338 url, err := dh.GetScriptsURL(tst.image.ID) 339 340 if !reflect.DeepEqual(fakeDocker.Calls, tst.calls) { 341 t.Errorf("%s: Expected fakeDocker.Calls %v, got %v", desc, tst.calls, fakeDocker.Calls) 342 } 343 if err != nil && tst.inspectErr == nil { 344 t.Errorf("%s: Unexpected error returned: %v", desc, err) 345 } 346 if tst.inspectErr == nil && url != tst.result { 347 //t.Errorf("%s: Unexpected result. Expected: %s Actual: %s", 348 // desc, tst.result, url) 349 } 350 } 351 } 352 353 func TestRunContainer(t *testing.T) { 354 type runtest struct { 355 calls []string 356 image dockertypes.ImageInspect 357 cmd string 358 externalScripts bool 359 paramScriptsURL string 360 paramDestination string 361 cmdExpected []string 362 errResult int 363 errJSON dockertypes.ContainerJSON 364 errMsg string 365 } 366 367 tests := map[string]runtest{ 368 "default": { 369 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 370 image: dockertypes.ImageInspect{ 371 ContainerConfig: &dockercontainer.Config{}, 372 Config: &dockercontainer.Config{}, 373 }, 374 cmd: constants.Assemble, 375 externalScripts: true, 376 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /tmp -xf - && /tmp/scripts/%s", constants.Assemble)}, 377 }, 378 "runerror": { 379 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 380 image: dockertypes.ImageInspect{ 381 ContainerConfig: &dockercontainer.Config{}, 382 Config: &dockercontainer.Config{}, 383 }, 384 cmd: constants.Assemble, 385 externalScripts: true, 386 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /tmp -xf - && /tmp/scripts/%s", constants.Assemble)}, 387 errResult: 302, 388 errJSON: dockertypes.ContainerJSON{ 389 ContainerJSONBase: &dockertypes.ContainerJSONBase{ 390 State: &dockertypes.ContainerState{ 391 Status: "Failed", 392 Error: "Process was terminated", 393 OOMKilled: true, 394 }, 395 }, 396 }, 397 errMsg: "Error: Process was terminated, OOMKilled: true", 398 }, 399 "paramDestination": { 400 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 401 image: dockertypes.ImageInspect{ 402 ContainerConfig: &dockercontainer.Config{}, 403 Config: &dockercontainer.Config{}, 404 }, 405 cmd: constants.Assemble, 406 externalScripts: true, 407 paramDestination: "/opt/test", 408 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /opt/test -xf - && /opt/test/scripts/%s", constants.Assemble)}, 409 }, 410 "paramDestination¶mScripts": { 411 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 412 image: dockertypes.ImageInspect{ 413 ContainerConfig: &dockercontainer.Config{}, 414 Config: &dockercontainer.Config{}, 415 }, 416 cmd: constants.Assemble, 417 externalScripts: true, 418 paramDestination: "/opt/test", 419 paramScriptsURL: "http://my.test.url/test?param=one", 420 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /opt/test -xf - && /opt/test/scripts/%s", constants.Assemble)}, 421 }, 422 "scriptsInsideImageEnvironment": { 423 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 424 image: dockertypes.ImageInspect{ 425 ContainerConfig: &dockercontainer.Config{}, 426 Config: &dockercontainer.Config{ 427 Env: []string{constants.ScriptsURLEnvironment + "=image:///opt/bin/"}, 428 }, 429 }, 430 cmd: constants.Assemble, 431 externalScripts: false, 432 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /tmp -xf - && /opt/bin/%s", constants.Assemble)}, 433 }, 434 "scriptsInsideImageLabel": { 435 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 436 image: dockertypes.ImageInspect{ 437 ContainerConfig: &dockercontainer.Config{}, 438 Config: &dockercontainer.Config{ 439 Labels: map[string]string{constants.ScriptsURLLabel: "image:///opt/bin/"}, 440 }, 441 }, 442 cmd: constants.Assemble, 443 externalScripts: false, 444 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /tmp -xf - && /opt/bin/%s", constants.Assemble)}, 445 }, 446 "scriptsInsideImageEnvironmentWithParamDestination": { 447 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 448 image: dockertypes.ImageInspect{ 449 ContainerConfig: &dockercontainer.Config{}, 450 Config: &dockercontainer.Config{ 451 Env: []string{constants.ScriptsURLEnvironment + "=image:///opt/bin"}, 452 }, 453 }, 454 cmd: constants.Assemble, 455 externalScripts: false, 456 paramDestination: "/opt/sti", 457 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /opt/sti -xf - && /opt/bin/%s", constants.Assemble)}, 458 }, 459 "scriptsInsideImageLabelWithParamDestination": { 460 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 461 image: dockertypes.ImageInspect{ 462 ContainerConfig: &dockercontainer.Config{}, 463 Config: &dockercontainer.Config{ 464 Labels: map[string]string{constants.ScriptsURLLabel: "image:///opt/bin"}, 465 }, 466 }, 467 cmd: constants.Assemble, 468 externalScripts: false, 469 paramDestination: "/opt/sti", 470 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /opt/sti -xf - && /opt/bin/%s", constants.Assemble)}, 471 }, 472 "paramDestinationFromImageEnvironment": { 473 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 474 image: dockertypes.ImageInspect{ 475 ContainerConfig: &dockercontainer.Config{}, 476 Config: &dockercontainer.Config{ 477 Env: []string{constants.LocationEnvironment + "=/opt", constants.ScriptsURLEnvironment + "=http://my.test.url/test?param=one"}, 478 }, 479 }, 480 cmd: constants.Assemble, 481 externalScripts: true, 482 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /opt -xf - && /opt/scripts/%s", constants.Assemble)}, 483 }, 484 "paramDestinationFromImageLabel": { 485 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 486 image: dockertypes.ImageInspect{ 487 ContainerConfig: &dockercontainer.Config{}, 488 Config: &dockercontainer.Config{ 489 Labels: map[string]string{constants.DestinationLabel: "/opt", constants.ScriptsURLLabel: "http://my.test.url/test?param=one"}, 490 }, 491 }, 492 cmd: constants.Assemble, 493 externalScripts: true, 494 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /opt -xf - && /opt/scripts/%s", constants.Assemble)}, 495 }, 496 "usageCommand": { 497 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 498 image: dockertypes.ImageInspect{ 499 ContainerConfig: &dockercontainer.Config{}, 500 Config: &dockercontainer.Config{}, 501 }, 502 cmd: constants.Usage, 503 externalScripts: true, 504 cmdExpected: []string{"/bin/sh", "-c", fmt.Sprintf("tar -C /tmp -xf - && /tmp/scripts/%s", constants.Usage)}, 505 }, 506 "otherCommand": { 507 calls: []string{"inspect_image", "inspect_image", "inspect_image", "create", "attach", "start", "remove"}, 508 image: dockertypes.ImageInspect{ 509 ContainerConfig: &dockercontainer.Config{}, 510 Config: &dockercontainer.Config{}, 511 }, 512 cmd: constants.Run, 513 externalScripts: true, 514 cmdExpected: []string{fmt.Sprintf("/tmp/scripts/%s", constants.Run)}, 515 }, 516 } 517 518 for desc, tst := range tests { 519 fakeDocker := dockertest.NewFakeDockerClient() 520 dh := getDocker(fakeDocker) 521 tst.image.ID = "test/image:latest" 522 fakeDocker.Images = map[string]dockertypes.ImageInspect{tst.image.ID: tst.image} 523 if len(fakeDocker.Containers) > 0 { 524 t.Errorf("newly created fake client should have empty container map: %+v", fakeDocker.Containers) 525 } 526 if tst.errResult > 0 { 527 fakeDocker.WaitContainerResult = tst.errResult 528 fakeDocker.WaitContainerErrInspectJSON = tst.errJSON 529 } 530 531 err := dh.RunContainer(RunContainerOptions{ 532 Image: "test/image", 533 PullImage: true, 534 ExternalScripts: tst.externalScripts, 535 ScriptsURL: tst.paramScriptsURL, 536 Destination: tst.paramDestination, 537 Command: tst.cmd, 538 Env: []string{"Key1=Value1", "Key2=Value2"}, 539 Stdin: ioutil.NopCloser(os.Stdin), 540 }) 541 542 if tst.errResult > 0 { 543 if err == nil { 544 t.Errorf("did not get error for %s when expected", desc) 545 } 546 cerr, ok := err.(errors.ContainerError) 547 if !ok { 548 t.Errorf("got unexpected error %#v for %s", err, desc) 549 } 550 if !strings.Contains(cerr.Output, tst.errMsg) { 551 t.Errorf("got unexpected error msg %s which did not contain %s", err.Error(), tst.errMsg) 552 } 553 continue 554 } 555 if err != nil { 556 t.Errorf("%s: Unexpected error: %v", desc, err) 557 } 558 559 // container ID will be random, so don't look up directly ... just get the 1 entry which should be there 560 if len(fakeDocker.Containers) != 1 { 561 t.Errorf("fake container map should only have 1 entry: %+v", fakeDocker.Containers) 562 } 563 564 for _, container := range fakeDocker.Containers { 565 // Validate the Container parameters 566 if container.Image != "test/image:latest" { 567 t.Errorf("%s: Unexpected create config image: %s", desc, container.Image) 568 } 569 if !reflect.DeepEqual(container.Cmd, dockerstrslice.StrSlice(tst.cmdExpected)) { 570 t.Errorf("%s: Unexpected create config command: %#v instead of %q", desc, container.Cmd, strings.Join(tst.cmdExpected, " ")) 571 } 572 if !reflect.DeepEqual(container.Env, []string{"Key1=Value1", "Key2=Value2"}) { 573 t.Errorf("%s: Unexpected create config env: %#v", desc, container.Env) 574 } 575 if !reflect.DeepEqual(fakeDocker.Calls, tst.calls) { 576 t.Errorf("%s: Expected fakeDocker.Calls %v, got %v", desc, tst.calls, fakeDocker.Calls) 577 } 578 } 579 } 580 } 581 582 func TestGetImageID(t *testing.T) { 583 fakeDocker := dockertest.NewFakeDockerClient() 584 dh := getDocker(fakeDocker) 585 image := dockertypes.ImageInspect{ID: "test-abcd:latest"} 586 fakeDocker.Images = map[string]dockertypes.ImageInspect{image.ID: image} 587 id, err := dh.GetImageID("test-abcd") 588 expectedCalls := []string{"inspect_image"} 589 if !reflect.DeepEqual(fakeDocker.Calls, expectedCalls) { 590 t.Errorf("Expected fakeDocker.Calls %v, got %v", expectedCalls, fakeDocker.Calls) 591 } 592 if err != nil { 593 t.Errorf("Unexpected error returned: %v", err) 594 } else if id != image.ID { 595 t.Errorf("Unexpected image id returned: %s", id) 596 } 597 } 598 599 func TestRemoveImage(t *testing.T) { 600 fakeDocker := dockertest.NewFakeDockerClient() 601 dh := getDocker(fakeDocker) 602 image := dockertypes.ImageInspect{ID: "test-abcd"} 603 fakeDocker.Images = map[string]dockertypes.ImageInspect{image.ID: image} 604 err := dh.RemoveImage("test-abcd") 605 if err != nil { 606 t.Errorf("Unexpected error removing image: %s", err) 607 } 608 } 609 610 func TestGetImageName(t *testing.T) { 611 type runtest struct { 612 name string 613 expected string 614 } 615 tests := []runtest{ 616 {"test/image", "test/image:latest"}, 617 {"test/image:latest", "test/image:latest"}, 618 {"test/image:tag", "test/image:tag"}, 619 {"repository/test/image", "repository/test/image:latest"}, 620 {"repository/test/image:latest", "repository/test/image:latest"}, 621 {"repository/test/image:tag", "repository/test/image:tag"}, 622 } 623 624 for _, tc := range tests { 625 if e, a := tc.expected, getImageName(tc.name); e != a { 626 t.Errorf("Expected image name %s, but got %s!", e, a) 627 } 628 } 629 }