diff --git a/pkg/container/client_test.go b/pkg/container/client_test.go index 02b31eb..6ccc93c 100644 --- a/pkg/container/client_test.go +++ b/pkg/container/client_test.go @@ -33,8 +33,8 @@ var _ = Describe("the client", func() { mockServer.Close() }) Describe("WarnOnHeadPullFailed", func() { - containerUnknown := *mockContainerWithImageName("unknown.repo/prefix/imagename:latest") - containerKnown := *mockContainerWithImageName("docker.io/prefix/imagename:latest") + containerUnknown := *MockContainer(WithImageName("unknown.repo/prefix/imagename:latest")) + containerKnown := *MockContainer(WithImageName("docker.io/prefix/imagename:latest")) When(`warn on head failure is set to "always"`, func() { c := dockerClient{ClientOptions: ClientOptions{WarnOnHeadFailed: WarnAlways}} @@ -64,7 +64,7 @@ var _ = Describe("the client", func() { When("the image consist of a pinned hash", func() { It("should gracefully fail with a useful message", func() { c := dockerClient{} - pinnedContainer := *mockContainerWithImageName("sha256:fa5269854a5e615e51a72b17ad3fd1e01268f278a6684c8ed3c5f0cdce3f230b") + pinnedContainer := *MockContainer(WithImageName("sha256:fa5269854a5e615e51a72b17ad3fd1e01268f278a6684c8ed3c5f0cdce3f230b")) c.PullImage(context.Background(), pinnedContainer) }) }) diff --git a/pkg/container/container_mock_test.go b/pkg/container/container_mock_test.go new file mode 100644 index 0000000..96a7834 --- /dev/null +++ b/pkg/container/container_mock_test.go @@ -0,0 +1,66 @@ +package container + +import ( + "github.com/docker/docker/api/types" + dockerContainer "github.com/docker/docker/api/types/container" + "github.com/docker/go-connections/nat" +) + +type MockContainerUpdate func(*types.ContainerJSON, *types.ImageInspect) + +func MockContainer(updates ...MockContainerUpdate) *Container { + containerInfo := types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + ID: "container_id", + Image: "image", + Name: "test-containrrr", + HostConfig: &dockerContainer.HostConfig{}, + }, + Config: &dockerContainer.Config{ + Labels: map[string]string{}, + }, + } + image := types.ImageInspect{ + ID: "image_id", + } + + for _, update := range updates { + update(&containerInfo, &image) + } + return NewContainer(&containerInfo, &image) +} + +func WithPortBindings(portBindingSources ...string) MockContainerUpdate { + return func(c *types.ContainerJSON, i *types.ImageInspect) { + portBindings := nat.PortMap{} + for _, pbs := range portBindingSources { + portBindings[nat.Port(pbs)] = []nat.PortBinding{} + } + c.HostConfig.PortBindings = portBindings + } +} + +func WithImageName(name string) MockContainerUpdate { + return func(c *types.ContainerJSON, i *types.ImageInspect) { + c.Config.Image = name + i.RepoTags = append(i.RepoTags, name) + } +} + +func WithLinks(links []string) MockContainerUpdate { + return func(c *types.ContainerJSON, i *types.ImageInspect) { + c.HostConfig.Links = links + } +} + +func WithLabels(labels map[string]string) MockContainerUpdate { + return func(c *types.ContainerJSON, i *types.ImageInspect) { + c.Config.Labels = labels + } +} + +func WithContainerState(state types.ContainerState) MockContainerUpdate { + return func(cnt *types.ContainerJSON, img *types.ImageInspect) { + cnt.State = &state + } +} diff --git a/pkg/container/container_test.go b/pkg/container/container_test.go index 6cd5c86..e75871b 100644 --- a/pkg/container/container_test.go +++ b/pkg/container/container_test.go @@ -1,8 +1,6 @@ package container import ( - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -12,7 +10,7 @@ var _ = Describe("the container", func() { Describe("VerifyConfiguration", func() { When("verifying a container with no image info", func() { It("should return an error", func() { - c := mockContainerWithPortBindings() + c := MockContainer(WithPortBindings()) c.imageInfo = nil err := c.VerifyConfiguration() Expect(err).To(Equal(errorNoImageInfo)) @@ -20,7 +18,7 @@ var _ = Describe("the container", func() { }) When("verifying a container with no container info", func() { It("should return an error", func() { - c := mockContainerWithPortBindings() + c := MockContainer(WithPortBindings()) c.containerInfo = nil err := c.VerifyConfiguration() Expect(err).To(Equal(errorNoContainerInfo)) @@ -28,7 +26,7 @@ var _ = Describe("the container", func() { }) When("verifying a container with no config", func() { It("should return an error", func() { - c := mockContainerWithPortBindings() + c := MockContainer(WithPortBindings()) c.containerInfo.Config = nil err := c.VerifyConfiguration() Expect(err).To(Equal(errorInvalidConfig)) @@ -36,7 +34,7 @@ var _ = Describe("the container", func() { }) When("verifying a container with no host config", func() { It("should return an error", func() { - c := mockContainerWithPortBindings() + c := MockContainer(WithPortBindings()) c.containerInfo.HostConfig = nil err := c.VerifyConfiguration() Expect(err).To(Equal(errorInvalidConfig)) @@ -44,14 +42,14 @@ var _ = Describe("the container", func() { }) When("verifying a container with no port bindings", func() { It("should not return an error", func() { - c := mockContainerWithPortBindings() + c := MockContainer(WithPortBindings()) err := c.VerifyConfiguration() Expect(err).ToNot(HaveOccurred()) }) }) When("verifying a container with port bindings, but no exposed ports", func() { It("should make the config compatible with updating", func() { - c := mockContainerWithPortBindings("80/tcp") + c := MockContainer(WithPortBindings("80/tcp")) c.containerInfo.Config.ExposedPorts = nil Expect(c.VerifyConfiguration()).To(Succeed()) @@ -61,7 +59,7 @@ var _ = Describe("the container", func() { }) When("verifying a container with port bindings and exposed ports is non-nil", func() { It("should return an error", func() { - c := mockContainerWithPortBindings("80/tcp") + c := MockContainer(WithPortBindings("80/tcp")) c.containerInfo.Config.ExposedPorts = map[nat.Port]struct{}{"80/tcp": {}} err := c.VerifyConfiguration() Expect(err).ToNot(HaveOccurred()) @@ -71,10 +69,10 @@ var _ = Describe("the container", func() { When("asked for metadata", func() { var c *Container BeforeEach(func() { - c = mockContainerWithLabels(map[string]string{ + c = MockContainer(WithLabels(map[string]string{ "com.centurylinklabs.watchtower.enable": "true", "com.centurylinklabs.watchtower": "true", - }) + })) }) It("should return its name on calls to .Name()", func() { name := c.Name() @@ -91,36 +89,28 @@ var _ = Describe("the container", func() { enabled, exists := c.Enabled() Expect(enabled).To(BeTrue()) - Expect(enabled).NotTo(BeFalse()) Expect(exists).To(BeTrue()) - Expect(exists).NotTo(BeFalse()) }) It("should return false, true if present but not true on calls to .Enabled()", func() { - c = mockContainerWithLabels(map[string]string{"com.centurylinklabs.watchtower.enable": "false"}) + c = MockContainer(WithLabels(map[string]string{"com.centurylinklabs.watchtower.enable": "false"})) enabled, exists := c.Enabled() Expect(enabled).To(BeFalse()) - Expect(enabled).NotTo(BeTrue()) Expect(exists).To(BeTrue()) - Expect(exists).NotTo(BeFalse()) }) It("should return false, false if not present on calls to .Enabled()", func() { - c = mockContainerWithLabels(map[string]string{"lol": "false"}) + c = MockContainer(WithLabels(map[string]string{"lol": "false"})) enabled, exists := c.Enabled() Expect(enabled).To(BeFalse()) - Expect(enabled).NotTo(BeTrue()) Expect(exists).To(BeFalse()) - Expect(exists).NotTo(BeTrue()) }) It("should return false, false if present but not parsable .Enabled()", func() { - c = mockContainerWithLabels(map[string]string{"com.centurylinklabs.watchtower.enable": "falsy"}) + c = MockContainer(WithLabels(map[string]string{"com.centurylinklabs.watchtower.enable": "falsy"})) enabled, exists := c.Enabled() Expect(enabled).To(BeFalse()) - Expect(enabled).NotTo(BeTrue()) Expect(exists).To(BeFalse()) - Expect(exists).NotTo(BeTrue()) }) When("checking if its a watchtower instance", func() { It("should return true if the label is set to true", func() { @@ -128,31 +118,31 @@ var _ = Describe("the container", func() { Expect(isWatchtower).To(BeTrue()) }) It("should return false if the label is present but set to false", func() { - c = mockContainerWithLabels(map[string]string{"com.centurylinklabs.watchtower": "false"}) + c = MockContainer(WithLabels(map[string]string{"com.centurylinklabs.watchtower": "false"})) isWatchtower := c.IsWatchtower() Expect(isWatchtower).To(BeFalse()) }) It("should return false if the label is not present", func() { - c = mockContainerWithLabels(map[string]string{"funny.label": "false"}) + c = MockContainer(WithLabels(map[string]string{"funny.label": "false"})) isWatchtower := c.IsWatchtower() Expect(isWatchtower).To(BeFalse()) }) It("should return false if there are no labels", func() { - c = mockContainerWithLabels(map[string]string{}) + c = MockContainer(WithLabels(map[string]string{})) isWatchtower := c.IsWatchtower() Expect(isWatchtower).To(BeFalse()) }) }) When("fetching the custom stop signal", func() { It("should return the signal if its set", func() { - c = mockContainerWithLabels(map[string]string{ + c = MockContainer(WithLabels(map[string]string{ "com.centurylinklabs.watchtower.stop-signal": "SIGKILL", - }) + })) stopSignal := c.StopSignal() Expect(stopSignal).To(Equal("SIGKILL")) }) It("should return an empty string if its not set", func() { - c = mockContainerWithLabels(map[string]string{}) + c = MockContainer(WithLabels(map[string]string{})) stopSignal := c.StopSignal() Expect(stopSignal).To(Equal("")) }) @@ -160,22 +150,22 @@ var _ = Describe("the container", func() { When("fetching the image name", func() { When("the zodiac label is present", func() { It("should fetch the image name from it", func() { - c = mockContainerWithLabels(map[string]string{ + c = MockContainer(WithLabels(map[string]string{ "com.centurylinklabs.zodiac.original-image": "the-original-image", - }) + })) imageName := c.ImageName() Expect(imageName).To(Equal(imageName)) }) }) It("should return the image name", func() { name := "image-name:3" - c = mockContainerWithImageName(name) + c = MockContainer(WithImageName(name)) imageName := c.ImageName() Expect(imageName).To(Equal(name)) }) It("should assume latest if no tag is supplied", func() { name := "image-name" - c = mockContainerWithImageName(name) + c = MockContainer(WithImageName(name)) imageName := c.ImageName() Expect(imageName).To(Equal(name + ":latest")) }) @@ -184,33 +174,33 @@ var _ = Describe("the container", func() { When("fetching container links", func() { When("the depends on label is present", func() { It("should fetch depending containers from it", func() { - c = mockContainerWithLabels(map[string]string{ + c = MockContainer(WithLabels(map[string]string{ "com.centurylinklabs.watchtower.depends-on": "postgres", - }) + })) links := c.Links() Expect(links).To(SatisfyAll(ContainElement("postgres"), HaveLen(1))) }) It("should fetch depending containers if there are many", func() { - c = mockContainerWithLabels(map[string]string{ + c = MockContainer(WithLabels(map[string]string{ "com.centurylinklabs.watchtower.depends-on": "postgres,redis", - }) + })) links := c.Links() Expect(links).To(SatisfyAll(ContainElement("postgres"), ContainElement("redis"), HaveLen(2))) }) It("should fetch depending containers if label is blank", func() { - c = mockContainerWithLabels(map[string]string{ + c = MockContainer(WithLabels(map[string]string{ "com.centurylinklabs.watchtower.depends-on": "", - }) + })) links := c.Links() Expect(links).To(HaveLen(0)) }) }) When("the depends on label is not present", func() { It("should fetch depending containers from host config links", func() { - c = mockContainerWithLinks([]string{ + c = MockContainer(WithLinks([]string{ "redis:test-containrrr", "postgres:test-containrrr", - }) + })) links := c.Links() Expect(links).To(SatisfyAll(ContainElement("redis"), ContainElement("postgres"), HaveLen(2))) }) @@ -219,10 +209,10 @@ var _ = Describe("the container", func() { When("there is a pre or post update timeout", func() { It("should return minute values", func() { - c = mockContainerWithLabels(map[string]string{ + c = MockContainer(WithLabels(map[string]string{ "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout": "3", "com.centurylinklabs.watchtower.lifecycle.post-update-timeout": "5", - }) + })) preTimeout := c.PreUpdateTimeout() Expect(preTimeout).To(Equal(3)) postTimeout := c.PostUpdateTimeout() @@ -232,53 +222,3 @@ var _ = Describe("the container", func() { }) }) - -func mockContainerWithPortBindings(portBindingSources ...string) *Container { - mockContainer := mockContainerWithLabels(nil) - mockContainer.imageInfo = &types.ImageInspect{} - hostConfig := &container.HostConfig{ - PortBindings: nat.PortMap{}, - } - for _, pbs := range portBindingSources { - hostConfig.PortBindings[nat.Port(pbs)] = []nat.PortBinding{} - } - mockContainer.containerInfo.HostConfig = hostConfig - return mockContainer -} - -func mockContainerWithImageName(name string) *Container { - mockContainer := mockContainerWithLabels(nil) - mockContainer.containerInfo.Config.Image = name - return mockContainer -} - -func mockContainerWithLinks(links []string) *Container { - content := types.ContainerJSON{ - ContainerJSONBase: &types.ContainerJSONBase{ - ID: "container_id", - Image: "image", - Name: "test-containrrr", - HostConfig: &container.HostConfig{ - Links: links, - }, - }, - Config: &container.Config{ - Labels: map[string]string{}, - }, - } - return NewContainer(&content, nil) -} - -func mockContainerWithLabels(labels map[string]string) *Container { - content := types.ContainerJSON{ - ContainerJSONBase: &types.ContainerJSONBase{ - ID: "container_id", - Image: "image", - Name: "test-containrrr", - }, - Config: &container.Config{ - Labels: labels, - }, - } - return NewContainer(&content, nil) -}