github.com/stevenmatthewt/agent@v3.5.4+incompatible/bootstrap/integration/docker_integration_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"runtime"
     5  	"testing"
     6  
     7  	"github.com/buildkite/bintest"
     8  )
     9  
    10  func argumentForCommand(cmd string) interface{} {
    11  	// This is unpleasant, but we have to work around the fact that we generate
    12  	// batch scripts for windows and plain commands for everything else
    13  	if runtime.GOOS == `windows` {
    14  		return bintest.MatchPattern(`buildkite-script-.+.bat$`)
    15  	}
    16  	return cmd
    17  }
    18  
    19  func TestRunningCommandWithDocker(t *testing.T) {
    20  	tester, err := NewBootstrapTester()
    21  	if err != nil {
    22  		t.Fatal(err)
    23  	}
    24  	defer tester.Close()
    25  
    26  	// Mock out the meta-data calls to the agent after checkout
    27  	agent := tester.MustMock(t, "buildkite-agent")
    28  	agent.
    29  		Expect("meta-data", "exists", "buildkite:git:commit").
    30  		AndExitWith(0)
    31  
    32  	env := []string{
    33  		"BUILDKITE_DOCKER=llamas",
    34  	}
    35  
    36  	jobId := "1111-1111-1111-1111"
    37  	imageId := "buildkite_" + jobId + "_image"
    38  	containerId := "buildkite_" + jobId + "_container"
    39  
    40  	docker := tester.MustMock(t, "docker")
    41  	docker.ExpectAll([][]interface{}{
    42  		{"build", "-f", "Dockerfile", "-t", imageId, "."},
    43  		{"run", "--name", containerId, imageId, argumentForCommand("true")},
    44  		{"rm", "-f", "-v", containerId},
    45  	})
    46  
    47  	expectCommandHooks("0", t, tester)
    48  
    49  	tester.RunAndCheck(t, env...)
    50  }
    51  
    52  func TestRunningCommandWithDockerAndCustomDockerfile(t *testing.T) {
    53  	tester, err := NewBootstrapTester()
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	defer tester.Close()
    58  
    59  	// Mock out the meta-data calls to the agent after checkout
    60  	agent := tester.MustMock(t, "buildkite-agent")
    61  	agent.
    62  		Expect("meta-data", "exists", "buildkite:git:commit").
    63  		AndExitWith(0)
    64  
    65  	env := []string{
    66  		"BUILDKITE_DOCKER=llamas",
    67  		"BUILDKITE_DOCKER_FILE=Dockerfile.llamas",
    68  	}
    69  
    70  	jobId := "1111-1111-1111-1111"
    71  	imageId := "buildkite_" + jobId + "_image"
    72  	containerId := "buildkite_" + jobId + "_container"
    73  
    74  	docker := tester.MustMock(t, "docker")
    75  	docker.ExpectAll([][]interface{}{
    76  		{"build", "-f", "Dockerfile.llamas", "-t", imageId, "."},
    77  		{"run", "--name", containerId, imageId, argumentForCommand("true")},
    78  		{"rm", "-f", "-v", containerId},
    79  	})
    80  
    81  	expectCommandHooks("0", t, tester)
    82  
    83  	tester.RunAndCheck(t, env...)
    84  }
    85  
    86  func TestRunningFailingCommandWithDocker(t *testing.T) {
    87  	tester, err := NewBootstrapTester()
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	defer tester.Close()
    92  
    93  	// Mock out the meta-data calls to the agent after checkout
    94  	agent := tester.MustMock(t, "buildkite-agent")
    95  	agent.
    96  		Expect("meta-data", "exists", "buildkite:git:commit").
    97  		AndExitWith(0)
    98  
    99  	env := []string{
   100  		"BUILDKITE_DOCKER=llamas",
   101  	}
   102  
   103  	jobId := "1111-1111-1111-1111"
   104  	imageId := "buildkite_" + jobId + "_image"
   105  	containerId := "buildkite_" + jobId + "_container"
   106  
   107  	docker := tester.MustMock(t, "docker")
   108  	docker.ExpectAll([][]interface{}{
   109  		{"build", "-f", "Dockerfile", "-t", imageId, "."},
   110  		{"rm", "-f", "-v", containerId},
   111  	})
   112  
   113  	docker.Expect("run", "--name", containerId, imageId, argumentForCommand("true")).
   114  		AndExitWith(1)
   115  
   116  	expectCommandHooks("1", t, tester)
   117  
   118  	if err = tester.Run(t, env...); err == nil {
   119  		t.Fatal("Expected bootstrap to fail")
   120  	}
   121  
   122  	tester.CheckMocks(t)
   123  }
   124  
   125  func TestRunningCommandWithDockerCompose(t *testing.T) {
   126  	tester, err := NewBootstrapTester()
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	defer tester.Close()
   131  
   132  	// Mock out the meta-data calls to the agent after checkout
   133  	agent := tester.MustMock(t, "buildkite-agent")
   134  	agent.
   135  		Expect("meta-data", "exists", "buildkite:git:commit").
   136  		AndExitWith(0)
   137  
   138  	env := []string{
   139  		"BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas",
   140  	}
   141  
   142  	projectName := "buildkite1111111111111111"
   143  
   144  	dockerCompose := tester.MustMock(t, "docker-compose")
   145  	dockerCompose.ExpectAll([][]interface{}{
   146  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "build", "--pull", "llamas"},
   147  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "run", "llamas", argumentForCommand("true")},
   148  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "kill"},
   149  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "rm", "--force", "--all", "-v"},
   150  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "down"},
   151  	})
   152  
   153  	expectCommandHooks("0", t, tester)
   154  
   155  	tester.RunAndCheck(t, env...)
   156  }
   157  
   158  func TestRunningFailingCommandWithDockerCompose(t *testing.T) {
   159  	tester, err := NewBootstrapTester()
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  	defer tester.Close()
   164  
   165  	// Mock out the meta-data calls to the agent after checkout
   166  	agent := tester.MustMock(t, "buildkite-agent")
   167  	agent.
   168  		Expect("meta-data", "exists", "buildkite:git:commit").
   169  		AndExitWith(0)
   170  
   171  	env := []string{
   172  		"BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas",
   173  	}
   174  
   175  	projectName := "buildkite1111111111111111"
   176  
   177  	dockerCompose := tester.MustMock(t, "docker-compose")
   178  	dockerCompose.ExpectAll([][]interface{}{
   179  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "build", "--pull", "llamas"},
   180  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "kill"},
   181  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "rm", "--force", "--all", "-v"},
   182  		{"-f", "docker-compose.yml", "-p", projectName, "--verbose", "down"},
   183  	})
   184  
   185  	dockerCompose.Expect("-f", "docker-compose.yml", "-p", projectName, "--verbose", "run", "llamas", argumentForCommand("true")).
   186  		AndWriteToStderr("Nope!").
   187  		AndExitWith(1)
   188  
   189  	expectCommandHooks("1", t, tester)
   190  
   191  	if err = tester.Run(t, env...); err == nil {
   192  		t.Fatal("Expected bootstrap to fail")
   193  	}
   194  
   195  	tester.CheckMocks(t)
   196  }
   197  
   198  func TestRunningCommandWithDockerComposeAndExtraConfig(t *testing.T) {
   199  	tester, err := NewBootstrapTester()
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  	defer tester.Close()
   204  
   205  	// Mock out the meta-data calls to the agent after checkout
   206  	agent := tester.MustMock(t, "buildkite-agent")
   207  	agent.
   208  		Expect("meta-data", "exists", "buildkite:git:commit").
   209  		AndExitWith(0)
   210  
   211  	env := []string{
   212  		"BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas",
   213  		"BUILDKITE_DOCKER_COMPOSE_FILE=dc1.yml:dc2.yml:dc3.yml",
   214  	}
   215  
   216  	projectName := "buildkite1111111111111111"
   217  
   218  	dockerCompose := tester.MustMock(t, "docker-compose")
   219  	dockerCompose.ExpectAll([][]interface{}{
   220  		{"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "build", "--pull", "llamas"},
   221  		{"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "run", "llamas", argumentForCommand("true")},
   222  		{"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "kill"},
   223  		{"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "rm", "--force", "--all", "-v"},
   224  		{"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "down"},
   225  	})
   226  
   227  	expectCommandHooks("0", t, tester)
   228  
   229  	tester.RunAndCheck(t, env...)
   230  }
   231  
   232  func TestRunningCommandWithDockerComposeAndBuildAll(t *testing.T) {
   233  	tester, err := NewBootstrapTester()
   234  	if err != nil {
   235  		t.Fatal(err)
   236  	}
   237  	defer tester.Close()
   238  
   239  	// Mock out the meta-data calls to the agent after checkout
   240  	agent := tester.MustMock(t, "buildkite-agent")
   241  	agent.
   242  		Expect("meta-data", "exists", "buildkite:git:commit").
   243  		AndExitWith(0)
   244  
   245  	env := []string{
   246  		"BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas",
   247  		"BUILDKITE_DOCKER_COMPOSE_BUILD_ALL=true",
   248  	}
   249  
   250  	dockerCompose := tester.MustMock(t, "docker-compose")
   251  	dockerCompose.IgnoreUnexpectedInvocations()
   252  	dockerCompose.Expect("-f", "docker-compose.yml", "-p", "buildkite1111111111111111", "--verbose", "build", "--pull").Once()
   253  
   254  	tester.RunAndCheck(t, env...)
   255  }
   256  
   257  func expectCommandHooks(exitStatus string, t *testing.T, tester *BootstrapTester) {
   258  	tester.ExpectGlobalHook("pre-command").Once()
   259  	tester.ExpectLocalHook("pre-command").Once()
   260  	tester.ExpectGlobalHook("post-command").Once()
   261  	tester.ExpectLocalHook("post-command").Once()
   262  
   263  	preExitFunc := func(c *bintest.Call) {
   264  		cmdExitStatus := c.GetEnv(`BUILDKITE_COMMAND_EXIT_STATUS`)
   265  		if cmdExitStatus != exitStatus {
   266  			t.Errorf("Expected an exit status of %s, got %v", exitStatus, cmdExitStatus)
   267  		}
   268  		c.Exit(0)
   269  	}
   270  
   271  	tester.ExpectGlobalHook("pre-exit").Once().AndCallFunc(preExitFunc)
   272  	tester.ExpectLocalHook("pre-exit").Once().AndCallFunc(preExitFunc)
   273  }