github.com/beanworks/dcm@v0.0.0-20230726194615-49d2d0417e04/src/dcm_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "io/ioutil" 8 "os" 9 "path" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 // ========== Mocked CmdMock struct as test helper for Dcm ========== 17 18 type CmdMock struct { 19 // CmdMock extends Cmd 20 Cmd 21 22 // Fields from CmdMock 23 name, dir string 24 args, env []string 25 } 26 27 func (c *CmdMock) Exec(name string, args ...string) Executable { 28 c.name = name 29 c.args = args 30 return c 31 } 32 33 func (c *CmdMock) Setdir(dir string) Executable { 34 c.dir = dir 35 return c 36 } 37 38 func (c *CmdMock) Setenv(env []string) Executable { 39 c.env = env 40 return c 41 } 42 43 func (c *CmdMock) Getenv() []string { 44 return c.env 45 } 46 47 func (c *CmdMock) Run() error { 48 switch c.name { 49 case "git": 50 if len(c.args) == 3 && c.args[0] == "clone" && 51 c.args[1] == "test-dcm-setup-error" { 52 return errors.New("exit status 1") 53 } 54 if len(c.args) == 2 && c.args[0] == "checkout" && 55 c.args[1] == "test-dcm-setup-error" { 56 return errors.New("exit status 1") 57 } 58 if len(c.args) == 3 && c.args[0] == "rev-parse" && 59 c.dir == "/test/dcm/git/rev-parse/error" { 60 return errors.New("exit status 1") 61 } 62 if len(c.args) == 2 && c.args[0] == "checkout" { 63 switch c.args[1] { 64 case "master", "test-dcm-update-error": 65 return errors.New("exit status 1") 66 } 67 } 68 if len(c.args) == 1 && c.args[0] == "pull" && 69 c.dir == "/test/dcm/git/pull/error" { 70 return errors.New("exit status 1") 71 } 72 case "docker-compose": 73 if c.dir == "/test/dcm/run/execute/error" { 74 return errors.New("exit status 1") 75 } 76 case "/bin/bash": 77 if len(c.args) == 1 && 78 c.args[0] == "test/dcm/run/init/error" { 79 return errors.New("exit status 1") 80 } 81 case "docker": 82 if len(c.args) == 4 && c.args[0] == "exec" && 83 c.args[2] == "dcmtest_failed_to_run_docker_exec_1" { 84 return errors.New("exit status 1") 85 } 86 if len(c.args) == 2 && c.args[0] == "rmi" && 87 c.args[1] == "dcmtest_bad" { 88 return errors.New("exit status 1") 89 } 90 if len(c.args) == 2 && c.args[0] == "kill" && 91 c.args[1] == "dcmtest_docker_kill_error_1" { 92 return errors.New("exit status 1") 93 } 94 if len(c.args) == 3 && c.args[0] == "rm" && 95 c.args[2] == "dcmtest_docker_rm_error_1" { 96 return errors.New("exit status 1") 97 } 98 } 99 return nil 100 } 101 102 func (c *CmdMock) Out() ([]byte, error) { 103 switch c.name { 104 case "docker": 105 if len(c.args) == 3 && c.args[0] == "ps" { 106 switch c.args[2] { 107 case "name=dcmtest_empty_container_id_": 108 return []byte(""), nil 109 case "name=dcmtest_ok_": 110 return []byte("dcmtest_ok_1"), nil 111 case "name=dcmtest_failed_to_run_docker_exec_": 112 return []byte("dcmtest_failed_to_run_docker_exec_1"), nil 113 case "name=dcmtest_docker_kill_error_": 114 return []byte("dcmtest_docker_kill_error_1"), nil 115 case "name=dcmtest_docker_rm_error_": 116 return []byte("dcmtest_docker_rm_error_1"), nil 117 default: 118 return []byte("error"), errors.New("exit status 1") 119 } 120 } 121 if len(c.args) == 1 && c.args[0] == "images" { 122 switch c.dir { 123 case "/test/docker/images/error": 124 return []byte("error"), errors.New("exit status 1") 125 case "/test/docker/images/remove/error": 126 return []byte("dcmtest_bad foobar bazqux"), nil 127 default: 128 return []byte("dcmtest_ok foobar bazqux"), nil 129 } 130 } 131 } 132 return []byte(""), nil 133 } 134 135 // ========== Here starts the real tests for Dcm ========== 136 137 func TestCommand(t *testing.T) { 138 var ( 139 code int 140 err error 141 ) 142 143 dir, err := ioutil.TempDir("", "dcm") 144 require.Nil(t, err) 145 defer os.Remove(dir) 146 147 dcm := NewDcm(NewConfig(), []string{}) 148 dcm.Config.Project = "dcmtest" 149 dcm.Config.Dir = dir 150 dcm.Cmd = &CmdMock{} 151 dcm.Cmd.Setdir("/test/dcm/git/rev-parse/ok") 152 153 tests := []struct { 154 name string 155 args []string 156 code int 157 }{ 158 { 159 name: "No args passed, print usage, and return code 1", 160 args: []string{}, 161 code: 1, 162 }, 163 { 164 name: "test command `dcm help`", 165 args: []string{"help"}, 166 code: 0, 167 }, 168 { 169 name: "test command `dcm setup`", 170 args: []string{"setup"}, 171 code: 0, 172 }, 173 { 174 name: "test command `dcm run`", 175 args: []string{"run"}, 176 code: 0, 177 }, 178 { 179 name: "test command `dcm build`", 180 args: []string{"build"}, 181 code: 0, 182 }, 183 { 184 name: "test command `dcm dir`", 185 args: []string{"dir"}, 186 code: 0, 187 }, 188 { 189 name: "test command `dcm shell`", 190 args: []string{"shell", "ok"}, 191 code: 0, 192 }, 193 { 194 name: "test command `dcm branch`", 195 args: []string{"branch", "dcm"}, 196 code: 0, 197 }, 198 { 199 name: "test command `dcm update`", 200 args: []string{"update"}, 201 code: 0, 202 }, 203 { 204 name: "dcm command `dcm purge`", 205 args: []string{"purge"}, 206 code: 0, 207 }, 208 { 209 name: "dcm command `dcm list`", 210 args: []string{"list"}, 211 code: 0, 212 }, 213 { 214 name: "Invalid args passed, print usage, and return code 127", 215 args: []string{"invalid"}, 216 code: 127, 217 }, 218 } 219 220 for n, test := range tests { 221 dcm.Args = test.args 222 code, err = dcm.Command() 223 assert.Equal(t, code, test.code, "[%d: %s] Incorrect error code returned", n, test.name) 224 assert.Nil(t, err, "[%d: %s] Non-nil error returned", n, test.name) 225 } 226 } 227 228 func TestSetup(t *testing.T) { 229 fixtures := []struct { 230 name string 231 config yamlConfig 232 code int 233 err error 234 }{ 235 { 236 name: "Negative case: failed to read git repository config", 237 config: yamlConfig{ 238 "service": yamlConfig{"build": "./build/dir"}, 239 }, 240 code: 1, 241 err: errors.New("Error reading git repository config for service [service]"), 242 }, 243 { 244 name: "Negative case: failed to clone git repository", 245 config: yamlConfig{ 246 "service": yamlConfig{ 247 "labels": yamlConfig{"dcm.repository": "test-dcm-setup-error"}, 248 }, 249 }, 250 code: 1, 251 err: errors.New("Error cloning git repository for service [service]: exit status 1"), 252 }, 253 { 254 name: "Negative case: failed to switch to pre-configured git branch", 255 config: yamlConfig{ 256 "service": yamlConfig{ 257 "labels": yamlConfig{ 258 "dcm.repository": "test-dcm-setup-ok", 259 "dcm.branch": "test-dcm-setup-error", 260 }, 261 }, 262 }, 263 code: 1, 264 err: errors.New("exit status 1"), 265 }, 266 { 267 name: "Positive case: success with docker hub image", 268 config: yamlConfig{ 269 "service": yamlConfig{ 270 "image": "docker-hub-image", 271 }, 272 }, 273 code: 0, 274 err: nil, 275 }, 276 { 277 name: "Positive case: success with local build", 278 config: yamlConfig{ 279 "service": yamlConfig{ 280 "labels": yamlConfig{ 281 "dcm.repository": "test-dcm-setup-ok", 282 "dcm.branch": "test-dcm-setup-ok", 283 }, 284 }, 285 }, 286 code: 0, 287 err: nil, 288 }, 289 } 290 291 td, err := ioutil.TempDir("", "dcm") 292 require.Nil(t, err) 293 defer os.Remove(td) 294 295 dcm := NewDcm(NewConfig(), []string{}) 296 dcm.Cmd = &CmdMock{} 297 dcm.Config.Srv = td 298 299 for n, test := range fixtures { 300 dcm.Config.Config = test.config 301 code, err := dcm.Setup() 302 assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name) 303 if test.err != nil { 304 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 305 } else { 306 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 307 } 308 } 309 } 310 311 func TestDoForEachService(t *testing.T) { 312 var ( 313 doSrv doForService 314 code int 315 err error 316 ) 317 318 dcm := NewDcm(NewConfig(), []string{}) 319 320 // Bad fixture data 321 fixtureBad := yamlConfig{ 322 "srv1": "config1", 323 "srv2": "config2", 324 } 325 // Good fixture data 326 fixtureGood := yamlConfig{ 327 "srv1": yamlConfig{ 328 "config": "value", 329 }, 330 "srv2": yamlConfig{ 331 "config": "value", 332 }, 333 } 334 335 // Negative case: silently fail when encountering bad config 336 dcm.Config.Config = fixtureBad 337 doSrv = func(service string, configs yamlConfig) (int, error) { 338 return 0, nil 339 } 340 code, err = dcm.doForEachService(doSrv) 341 assert.Equal(t, 1, code) 342 assert.Error(t, err) 343 344 // Negative case: fail with error 345 dcm.Config.Config = fixtureGood 346 doSrv = func(service string, configs yamlConfig) (int, error) { 347 return 1, errors.New("Error") 348 } 349 code, err = dcm.doForEachService(doSrv) 350 assert.Equal(t, 1, code) 351 assert.Error(t, err) 352 353 // Positive case: success 354 dcm.Config.Config = fixtureGood 355 doSrv = func(service string, configs yamlConfig) (int, error) { 356 return 0, nil 357 } 358 code, err = dcm.doForEachService(doSrv) 359 assert.Equal(t, 0, code) 360 assert.NoError(t, err) 361 } 362 363 func TestRun(t *testing.T) { 364 var ( 365 code int 366 err error 367 ) 368 369 dcm := NewDcm(NewConfig(), []string{}) 370 dcm.Cmd = &CmdMock{} 371 372 tests := []struct { 373 name string 374 args []string 375 code int 376 }{ 377 { 378 name: "No args passed, run `dcm run up` as default option", 379 args: []string{}, 380 code: 0, 381 }, 382 { 383 name: "dcm command `dcm run execute`", 384 args: []string{"execute"}, 385 code: 0, 386 }, 387 { 388 name: "dcm command `dcm run init`", 389 args: []string{"init"}, 390 code: 0, 391 }, 392 { 393 name: "dcm command `dcm run pre-init`", 394 args: []string{"pre-init"}, 395 code: 0, 396 }, 397 { 398 name: "dcm command `dcm run build`", 399 args: []string{"build"}, 400 code: 0, 401 }, 402 { 403 name: "dcm command `dcm run start`", 404 args: []string{"start"}, 405 code: 0, 406 }, 407 { 408 name: "dcm command `dcm run stop`", 409 args: []string{"stop"}, 410 code: 0, 411 }, 412 { 413 name: "dcm command `dcm run restart`", 414 args: []string{"restart"}, 415 code: 0, 416 }, 417 { 418 name: "dcm command `dcm run up`", 419 args: []string{"up"}, 420 code: 0, 421 }, 422 } 423 424 for n, test := range tests { 425 code, err = dcm.Run(test.args...) 426 assert.Equal(t, code, test.code, "[%d: %s] Incorrect error code returned", n, test.name) 427 assert.Nil(t, err, "[%d: %s] Non-nil error returned", n, test.name) 428 } 429 } 430 431 func TestRunExecute(t *testing.T) { 432 fixtures := []struct { 433 name, dir string 434 code int 435 }{ 436 { 437 name: "Negative case: failed to run docker-compose command", 438 dir: "/test/dcm/run/execute/error", 439 code: 1, 440 }, 441 { 442 name: "Positive case: success", 443 dir: "/test/dcm/run/execute/ok", 444 code: 0, 445 }, 446 } 447 448 dcm := NewDcm(NewConfig(), []string{}) 449 dcm.Cmd = &CmdMock{} 450 451 for n, test := range fixtures { 452 dcm.Config.Dir = test.dir 453 code, err := dcm.runExecute() 454 assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name) 455 if test.code == 1 { 456 assert.Error(t, err, "[%d: %s] Incorrect error returned", n, test.name) 457 } else { 458 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 459 } 460 } 461 } 462 463 func TestRunInit(t *testing.T) { 464 fixtures := []struct { 465 name string 466 config yamlConfig 467 code int 468 err error 469 }{ 470 { 471 name: "Negative case: config has no init script", 472 config: yamlConfig{ 473 "service": yamlConfig{ 474 "labels": yamlConfig{ 475 "dcm.test": "test", 476 }, 477 }, 478 }, 479 code: 0, 480 err: nil, 481 }, 482 { 483 name: "Negative case: failed to execute init script", 484 config: yamlConfig{ 485 "service": yamlConfig{ 486 "labels": yamlConfig{ 487 "dcm.initscript": "test/dcm/run/init/error", 488 }, 489 }, 490 }, 491 code: 1, 492 err: errors.New("Error executing init script [test/dcm/run/init/error] for service [service]: exit status 1"), 493 }, 494 { 495 name: "Positive case: success", 496 config: yamlConfig{ 497 "service": yamlConfig{ 498 "labels": yamlConfig{ 499 "dcm.initscript": "test/dcm/run/init/ok", 500 }, 501 }, 502 }, 503 code: 0, 504 err: nil, 505 }, 506 } 507 508 dcm := NewDcm(NewConfig(), []string{}) 509 dcm.Cmd = &CmdMock{} 510 511 for n, test := range fixtures { 512 dcm.Config.Config = test.config 513 code, err := dcm.runInit() 514 assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name) 515 if test.err != nil { 516 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 517 } else { 518 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 519 } 520 } 521 } 522 523 func TestRunPreInit(t *testing.T) { 524 fixtures := []struct { 525 name string 526 config yamlConfig 527 code int 528 err error 529 }{ 530 { 531 name: "Negative case: config has no pre-init script", 532 config: yamlConfig{ 533 "service": yamlConfig{ 534 "labels": yamlConfig{ 535 "dcm.test": "test", 536 }, 537 }, 538 }, 539 code: 0, 540 err: nil, 541 }, 542 { 543 name: "Negative case: failed to execute pre-init script", 544 config: yamlConfig{ 545 "service": yamlConfig{ 546 "labels": yamlConfig{ 547 "dcm.pre_initscript": "test/dcm/run/init/error", 548 }, 549 }, 550 }, 551 code: 1, 552 err: errors.New("Error executing pre-init script [test/dcm/run/init/error] for service [service]: exit status 1"), 553 }, 554 { 555 name: "Positive case: success", 556 config: yamlConfig{ 557 "service": yamlConfig{ 558 "labels": yamlConfig{ 559 "dcm.pre_initscript": "test/dcm/run/init/ok", 560 }, 561 }, 562 }, 563 code: 0, 564 err: nil, 565 }, 566 } 567 568 dcm := NewDcm(NewConfig(), []string{}) 569 dcm.Cmd = &CmdMock{} 570 571 for n, test := range fixtures { 572 dcm.Config.Config = test.config 573 code, err := dcm.runInit() 574 assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name) 575 if test.err != nil { 576 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 577 } else { 578 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 579 } 580 } 581 } 582 583 func TestDir(t *testing.T) { 584 dir, err := ioutil.TempDir("", "dcm") 585 require.Nil(t, err) 586 srv, err := ioutil.TempDir(dir, "service") 587 require.Nil(t, err) 588 defer os.RemoveAll(dir) 589 590 dcm := NewDcm(NewConfig(), []string{}) 591 var out string 592 593 // Test Dir() without args 594 out = helperTestOsStdout(t, func() { 595 dcm.Config.Dir = dir 596 dcm.Dir() 597 }) 598 assert.Equal(t, dir, out) 599 600 // Test Dir() with args, not exists, fall back to dcm.Config.Dir 601 out = helperTestOsStdout(t, func() { 602 dcm.Config.Srv = dir 603 dcm.Dir("not_exists") 604 }) 605 assert.Equal(t, dir, out) 606 607 // Test Dir() with args 608 out = helperTestOsStdout(t, func() { 609 dcm.Config.Srv = dir 610 dcm.Dir(path.Base(srv)) 611 }) 612 assert.Equal(t, srv, out) 613 } 614 615 func helperTestOsStdout(t *testing.T, fn func()) (out string) { 616 // Capture stdout 617 stdout := os.Stdout 618 r, w, err := os.Pipe() 619 require.Nil(t, err) 620 os.Stdout = w 621 outC := make(chan string) 622 623 go func() { 624 var buf bytes.Buffer 625 _, err := io.Copy(&buf, r) 626 r.Close() 627 require.Nil(t, err) 628 outC <- buf.String() 629 }() 630 631 fn() 632 633 w.Close() 634 os.Stdout = stdout 635 out = <-outC 636 637 return 638 } 639 640 func TestShell(t *testing.T) { 641 var ( 642 code int 643 err error 644 ) 645 646 dcm := NewDcm(NewConfig(), []string{}) 647 dcm.Cmd = &CmdMock{} 648 dcm.Config.Project = "dcmtest" 649 650 // Negative case: failed when there is no arg passed 651 code, err = dcm.Shell() 652 assert.Equal(t, 1, code) 653 assert.EqualError(t, err, "Error: no service name specified.") 654 655 // Negative case: failed to get docker container id 656 code, err = dcm.Shell("failed_to_get_container_id") 657 assert.Equal(t, 1, code) 658 assert.EqualError(t, err, "exit status 1: error") 659 660 // Negative case: failed to run docker exec command 661 code, err = dcm.Shell("failed_to_run_docker_exec") 662 assert.Equal(t, 1, code) 663 assert.EqualError(t, err, "exit status 1") 664 665 // Positive case: success 666 code, err = dcm.Shell("ok") 667 assert.Equal(t, 0, code) 668 assert.NoError(t, err) 669 } 670 671 func TestGetContainerId(t *testing.T) { 672 fixtures := []struct { 673 name, service, cid string 674 err error 675 }{ 676 { 677 name: "Negative case: failed to get docker container id", 678 service: "docker_ps_error", 679 cid: "", 680 err: errors.New("exit status 1: error"), 681 }, 682 { 683 name: "Negative case: got an empty container id", 684 service: "empty_container_id", 685 cid: "", 686 err: nil, 687 }, 688 { 689 name: "Positive case: success", 690 service: "ok", 691 cid: "dcmtest_ok_1", 692 err: nil, 693 }, 694 } 695 696 dcm := NewDcm(NewConfig(), []string{}) 697 dcm.Cmd = &CmdMock{} 698 dcm.Config.Project = "dcmtest" 699 700 for n, test := range fixtures { 701 cid, err := dcm.getContainerId(test.service, "-qf") 702 assert.Equal(t, test.cid, cid, "[%d: %s] Incorrect docker container ID returned", n, test.name) 703 if test.err != nil { 704 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 705 } else { 706 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 707 } 708 } 709 } 710 711 func TestGetImageRepository(t *testing.T) { 712 fixtures := []struct { 713 name, dir, service, repo string 714 err error 715 }{ 716 { 717 name: "Negative case: failed to execute docker images", 718 dir: "/test/docker/images/error", 719 service: "empty_image_repo", 720 repo: "", 721 err: errors.New("exit status 1: error"), 722 }, 723 { 724 name: "Negative case: service image repo name is not in docker images list", 725 dir: "/test/docker/images/ok", 726 service: "empty_image_repo", 727 repo: "", 728 err: nil, 729 }, 730 { 731 name: "Positive case: success", 732 dir: "/test/docker/images/ok", 733 service: "ok", 734 repo: "dcmtest_ok", 735 err: nil, 736 }, 737 } 738 739 dcm := NewDcm(NewConfig(), []string{}) 740 dcm.Cmd = &CmdMock{} 741 dcm.Config.Project = "dcmtest" 742 743 for n, test := range fixtures { 744 dcm.Cmd.Setdir(test.dir) 745 repo, err := dcm.getImageRepository(test.service) 746 assert.Equal(t, test.repo, repo, "[%d: %s] Incorrect docker image repository name returned", n, test.name) 747 if test.err != nil { 748 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 749 } else { 750 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 751 } 752 } 753 } 754 755 func TestBranchForOne(t *testing.T) { 756 var ( 757 code int 758 err error 759 ) 760 761 dir, err := ioutil.TempDir("", "dcm") 762 require.Nil(t, err) 763 srv, err := ioutil.TempDir(dir, "service") 764 require.Nil(t, err) 765 defer os.RemoveAll(dir) 766 767 dcm := NewDcm(NewConfig(), []string{}) 768 dcm.Cmd = &CmdMock{} 769 770 // Negative case: get dcm branch failed at os.Chdir() 771 dcm.Config.Dir = "/fake/dcm/dir" 772 code, err = dcm.branchForOne("dcm") 773 assert.Equal(t, 0, code) 774 assert.EqualError(t, err, "chdir /fake/dcm/dir: no such file or directory") 775 776 // Negative case: git failed to get dcm branch 777 dcm.Config.Dir = dir 778 dcm.Cmd.Setdir("/test/dcm/git/rev-parse/error") 779 code, err = dcm.branchForOne("dcm") 780 assert.Equal(t, 0, code) 781 assert.EqualError(t, err, "exit status 1") 782 783 // Negative case: service not exists 784 dcm.Config.Srv = "/fake/dcm/srv" 785 code, err = dcm.branchForOne("invalid") 786 assert.Equal(t, 0, code) 787 assert.EqualError(t, err, "Service not exists.") 788 789 // Negative case: get service branch failed at os.Chdir() 790 dcm.Config.Srv = "/fake/dcm/srv" 791 dcm.Config.Config = yamlConfig{"service": yamlConfig{}} 792 code, err = dcm.branchForOne("service") 793 assert.Equal(t, 0, code) 794 assert.EqualError(t, err, "chdir /fake/dcm/srv/service: no such file or directory") 795 796 // Negative case: git failed to get service branch 797 dcm.Config.Srv = dir 798 dcm.Config.Config = yamlConfig{path.Base(srv): yamlConfig{}} 799 dcm.Cmd.Setdir("/test/dcm/git/rev-parse/error") 800 code, err = dcm.branchForOne(path.Base(srv)) 801 assert.Equal(t, 0, code) 802 assert.EqualError(t, err, "exit status 1") 803 804 // Positive case: success with a service using docker hub image 805 dcm.Config.Config = yamlConfig{"service": yamlConfig{"image": "docker-hub-image"}} 806 code, err = dcm.branchForOne("service") 807 assert.Equal(t, 0, code) 808 assert.NoError(t, err) 809 810 // Positive case: success with dcm branch 811 dcm.Config.Dir = dir 812 dcm.Cmd.Setdir("/test/dcm/git/rev-parse/ok") 813 code, err = dcm.branchForOne("dcm") 814 assert.Equal(t, 0, code) 815 assert.NoError(t, err) 816 } 817 818 func TestUpdateForOne(t *testing.T) { 819 dir, err := ioutil.TempDir("", "dcm") 820 require.Nil(t, err) 821 srv, err := ioutil.TempDir(dir, "service") 822 require.Nil(t, err) 823 defer os.RemoveAll(dir) 824 825 service := path.Base(srv) 826 827 dcm := NewDcm(NewConfig(), []string{}) 828 dcm.Cmd = &CmdMock{} 829 830 fixtures := []struct { 831 name, srv, dir string 832 config yamlConfig 833 service string 834 code int 835 err error 836 }{ 837 { 838 name: "Negative case: service not exists", 839 dir: "", 840 srv: "", 841 config: yamlConfig{}, 842 service: "invalid", 843 code: 0, 844 err: errors.New("Service not exists."), 845 }, 846 { 847 name: "Negative case: service not updateable", 848 dir: "", 849 srv: "", 850 config: yamlConfig{ 851 "service": yamlConfig{ 852 "labels": yamlConfig{ 853 "dcm.updateable": "false", 854 }, 855 }, 856 }, 857 service: "service", 858 code: 0, 859 err: errors.New("Service not updateable. Skipping the update."), 860 }, 861 { 862 name: "Negative case: failed to os.Chdir()", 863 dir: "/test/dcm/update", 864 srv: "/test/dcm/dir/srv/testproj", 865 config: yamlConfig{ 866 "invalid": yamlConfig{ 867 "folder": "test", 868 }, 869 }, 870 service: "invalid", 871 code: 0, 872 err: errors.New("chdir /test/dcm/dir/srv/testproj/invalid: no such file or directory"), 873 }, 874 { 875 name: "Negative case: cannot read default branch config, use master instead, and got `git checkout` error", 876 dir: "/test/dcm/update", 877 srv: dir, 878 config: yamlConfig{ 879 service: yamlConfig{ 880 "labels": yamlConfig{ 881 "dcm.some.other": "label", 882 }, 883 }, 884 }, 885 service: service, 886 code: 0, 887 err: errors.New("exit status 1"), 888 }, 889 { 890 name: "Negative case: failed to execute `git checkout`", 891 dir: "/test/dcm/update", 892 srv: dir, 893 config: yamlConfig{ 894 service: yamlConfig{ 895 "labels": yamlConfig{ 896 "dcm.branch": "test-dcm-update-error", 897 }, 898 }, 899 }, 900 service: service, 901 code: 0, 902 err: errors.New("exit status 1"), 903 }, 904 { 905 name: "Negative case: failed to execute `git pull`", 906 dir: "/test/dcm/git/pull/error", 907 srv: dir, 908 config: yamlConfig{ 909 service: yamlConfig{ 910 "labels": yamlConfig{ 911 "dcm.branch": "test-dcm-update-ok", 912 }, 913 }, 914 }, 915 service: service, 916 code: 0, 917 err: errors.New("exit status 1"), 918 }, 919 { 920 name: "Positive case: success with docker hub image", 921 dir: "", 922 srv: "", 923 config: yamlConfig{ 924 "service": yamlConfig{ 925 "image": "docker-hub-image", 926 }, 927 }, 928 service: "service", 929 code: 0, 930 err: nil, 931 }, 932 { 933 name: "Positive case: success with local build", 934 dir: "/test/dcm/update", 935 srv: dir, 936 config: yamlConfig{ 937 service: yamlConfig{ 938 "labels": yamlConfig{ 939 "dcm.branch": "test-dcm-update-ok", 940 }, 941 }, 942 }, 943 service: service, 944 code: 0, 945 err: nil, 946 }, 947 } 948 949 for n, test := range fixtures { 950 dcm.Cmd.Setdir(test.dir) 951 dcm.Config.Srv = test.srv 952 dcm.Config.Config = test.config 953 code, err := dcm.updateForOne(test.service) 954 assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name) 955 if test.err != nil { 956 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 957 } else { 958 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 959 } 960 } 961 } 962 963 func TestPurge(t *testing.T) { 964 var ( 965 code int 966 err error 967 ) 968 969 dcm := NewDcm(NewConfig(), []string{}) 970 dcm.Cmd = &CmdMock{} 971 972 tests := []struct { 973 name string 974 args []string 975 code int 976 }{ 977 { 978 name: "No args passed, run `dcm purge containers` as default option", 979 args: []string{}, 980 code: 0, 981 }, 982 { 983 name: "dcm command `dcm purge images`", 984 args: []string{"images"}, 985 code: 0, 986 }, 987 { 988 name: "dcm command `dcm run containers`", 989 args: []string{"containers"}, 990 code: 0, 991 }, 992 { 993 name: "dcm command `dcm run all`", 994 args: []string{"all"}, 995 code: 0, 996 }, 997 } 998 999 for n, test := range tests { 1000 code, err = dcm.Purge(test.args...) 1001 assert.Equal(t, code, test.code, "[%d: %s] Incorrect error code returned", n, test.name) 1002 assert.Nil(t, err, "[%d: %s] Non-nil error returned", n, test.name) 1003 } 1004 } 1005 1006 func TestPurgeImages(t *testing.T) { 1007 fixtures := []struct { 1008 name, dir string 1009 config yamlConfig 1010 code int 1011 err error 1012 }{ 1013 { 1014 name: "Negative case: failed to get image repo name", 1015 dir: "/test/docker/images/error", 1016 config: yamlConfig{ 1017 "service": yamlConfig{ 1018 "test": "purgeImages", 1019 }, 1020 }, 1021 code: 0, 1022 err: nil, 1023 }, 1024 { 1025 name: "Negative case: failed to execute `docker rmi`", 1026 dir: "/test/docker/images/remove/error", 1027 config: yamlConfig{ 1028 "bad": yamlConfig{ 1029 "test": "purgeImages", 1030 }, 1031 }, 1032 code: 0, 1033 err: nil, 1034 }, 1035 { 1036 name: "Positive case: success", 1037 dir: "/test/docker/images/ok", 1038 config: yamlConfig{ 1039 "ok": yamlConfig{ 1040 "test": "purgeImages", 1041 }, 1042 }, 1043 code: 0, 1044 err: nil, 1045 }, 1046 } 1047 1048 dcm := NewDcm(NewConfig(), []string{}) 1049 dcm.Cmd = &CmdMock{} 1050 dcm.Config.Project = "dcmtest" 1051 1052 for n, test := range fixtures { 1053 dcm.Cmd.Setdir(test.dir) 1054 dcm.Config.Config = test.config 1055 code, err := dcm.purgeImages() 1056 assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name) 1057 if test.err != nil { 1058 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 1059 } else { 1060 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 1061 } 1062 } 1063 } 1064 1065 func TestPurgeContainers(t *testing.T) { 1066 fixtures := []struct { 1067 name string 1068 config yamlConfig 1069 code int 1070 err error 1071 }{ 1072 { 1073 name: "Negative case: failed to get container id", 1074 config: yamlConfig{ 1075 "docker_ps_error": yamlConfig{ 1076 "test": "purgeContainers", 1077 }, 1078 }, 1079 code: 0, 1080 err: nil, 1081 }, 1082 { 1083 name: "Negative case: failed to execute `docker kill`", 1084 config: yamlConfig{ 1085 "docker_kill_error": yamlConfig{ 1086 "test": "purgeContainers", 1087 }, 1088 }, 1089 code: 0, 1090 err: nil, 1091 }, 1092 { 1093 name: "Negative case: failed to execute `docker rm`", 1094 config: yamlConfig{ 1095 "docker_rm_error": yamlConfig{ 1096 "test": "purgeContainers", 1097 }, 1098 }, 1099 code: 0, 1100 err: nil, 1101 }, 1102 { 1103 name: "Positive case: success", 1104 config: yamlConfig{ 1105 "ok": yamlConfig{ 1106 "test": "purgeContainers", 1107 }, 1108 }, 1109 code: 0, 1110 err: nil, 1111 }, 1112 } 1113 1114 dcm := NewDcm(NewConfig(), []string{}) 1115 dcm.Cmd = &CmdMock{} 1116 dcm.Config.Project = "dcmtest" 1117 1118 for n, test := range fixtures { 1119 dcm.Config.Config = test.config 1120 code, err := dcm.purgeContainers() 1121 assert.Equal(t, test.code, code, "[%d: %s] Incorrect error code returned", n, test.name) 1122 if test.err != nil { 1123 assert.EqualError(t, err, test.err.Error(), "[%d: %s] Incorrect error returned", n, test.name) 1124 } else { 1125 assert.NoError(t, err, "[%d: %s] Non-nil error returned", n, test.name) 1126 } 1127 } 1128 } 1129 1130 func TestList(t *testing.T) { 1131 out := helperTestOsStdout(t, func() { 1132 dcm := NewDcm(NewConfig(), []string{}) 1133 dcm.Config.Config = yamlConfig{ 1134 "service": yamlConfig{}, 1135 } 1136 dcm.List() 1137 }) 1138 assert.Equal(t, "service\n", out) 1139 } 1140 1141 func TestUsage(t *testing.T) { 1142 out := helperTestOsStdout(t, func() { 1143 dcm := NewDcm(NewConfig(), []string{}) 1144 dcm.Usage() 1145 }) 1146 1147 assert.Contains(t, out, "DCM (Docker-Compose Manager)\n") 1148 assert.Contains(t, out, "Usage:\n") 1149 assert.Contains(t, out, "Example:\n") 1150 }