package actions_test import ( "github.com/containrrr/watchtower/internal/actions" "github.com/containrrr/watchtower/pkg/container" "github.com/containrrr/watchtower/pkg/types" dockerContainer "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" "time" . "github.com/containrrr/watchtower/internal/actions/mocks" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("the update action", func() { var client MockClient When("watchtower has been instructed to clean up", func() { BeforeEach(func() { pullImages := false removeVolumes := false //goland:noinspection GoBoolExpressions client = CreateMockClient( &TestData{ NameOfContainerToKeep: "test-container-02", Containers: []container.Container{ CreateMockContainer( "test-container-01", "test-container-01", "fake-image:latest", time.Now().AddDate(0, 0, -1)), CreateMockContainer( "test-container-02", "test-container-02", "fake-image:latest", time.Now()), CreateMockContainer( "test-container-02", "test-container-02", "fake-image:latest", time.Now()), }, }, pullImages, removeVolumes, ) }) When("there are multiple containers using the same image", func() { It("should only try to remove the image once", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1)) }) }) When("there are multiple containers using different images", func() { It("should try to remove each of them", func() { client.TestData.Containers = append( client.TestData.Containers, CreateMockContainer( "unique-test-container", "unique-test-container", "unique-fake-image:latest", time.Now(), ), ) _, err := actions.Update(client, types.UpdateParams{Cleanup: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(2)) }) }) When("performing a rolling restart update", func() { It("should try to remove the image once", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true, RollingRestart: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1)) }) }) }) When("watchtower has been instructed to monitor only", func() { When("certain containers are set to monitor only", func() { BeforeEach(func() { client = CreateMockClient( &TestData{ NameOfContainerToKeep: "test-container-02", Containers: []container.Container{ CreateMockContainer( "test-container-01", "test-container-01", "fake-image1:latest", time.Now()), CreateMockContainerWithConfig( "test-container-02", "test-container-02", "fake-image2:latest", false, false, time.Now(), &dockerContainer.Config{ Labels: map[string]string{ "com.centurylinklabs.watchtower.monitor-only": "true", }, }), }, }, false, false, ) }) It("should not update those containers", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1)) }) }) When("monitor only is set globally", func() { BeforeEach(func() { client = CreateMockClient( &TestData{ Containers: []container.Container{ CreateMockContainer( "test-container-01", "test-container-01", "fake-image:latest", time.Now()), CreateMockContainer( "test-container-02", "test-container-02", "fake-image:latest", time.Now()), }, }, false, false, ) }) It("should not update any containers", func() { _, err := actions.Update(client, types.UpdateParams{MonitorOnly: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(0)) }) }) }) When("watchtower has been instructed to run lifecycle hooks", func() { When("prupddate script returns 1", func() { BeforeEach(func() { client = CreateMockClient( &TestData{ //NameOfContainerToKeep: "test-container-02", Containers: []container.Container{ CreateMockContainerWithConfig( "test-container-02", "test-container-02", "fake-image2:latest", true, false, time.Now(), &dockerContainer.Config{ Labels: map[string]string{ "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout": "190", "com.centurylinklabs.watchtower.lifecycle.pre-update": "/PreUpdateReturn1.sh", }, ExposedPorts: map[nat.Port]struct{}{}, }), }, }, false, false, ) }) It("should not update those containers", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true, LifecycleHooks: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(0)) }) }) When("prupddate script returns 75", func() { BeforeEach(func() { client = CreateMockClient( &TestData{ //NameOfContainerToKeep: "test-container-02", Containers: []container.Container{ CreateMockContainerWithConfig( "test-container-02", "test-container-02", "fake-image2:latest", true, false, time.Now(), &dockerContainer.Config{ Labels: map[string]string{ "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout": "190", "com.centurylinklabs.watchtower.lifecycle.pre-update": "/PreUpdateReturn75.sh", }, ExposedPorts: map[nat.Port]struct{}{}, }), }, }, false, false, ) }) It("should not update those containers", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true, LifecycleHooks: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(0)) }) }) When("prupddate script returns 0", func() { BeforeEach(func() { client = CreateMockClient( &TestData{ //NameOfContainerToKeep: "test-container-02", Containers: []container.Container{ CreateMockContainerWithConfig( "test-container-02", "test-container-02", "fake-image2:latest", true, false, time.Now(), &dockerContainer.Config{ Labels: map[string]string{ "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout": "190", "com.centurylinklabs.watchtower.lifecycle.pre-update": "/PreUpdateReturn0.sh", }, ExposedPorts: map[nat.Port]struct{}{}, }), }, }, false, false, ) }) It("should update those containers", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true, LifecycleHooks: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1)) }) }) When("container is linked to restarting containers", func() { It("should be marked for restart", func() { provider := CreateMockContainerWithConfig( "test-container-provider", "/test-container-provider", "fake-image2:latest", true, false, time.Now(), &dockerContainer.Config{ Labels: map[string]string{}, ExposedPorts: map[nat.Port]struct{}{}, }) provider.Stale = true consumer := CreateMockContainerWithConfig( "test-container-consumer", "/test-container-consumer", "fake-image3:latest", true, false, time.Now(), &dockerContainer.Config{ Labels: map[string]string{ "com.centurylinklabs.watchtower.depends-on": "test-container-provider", }, ExposedPorts: map[nat.Port]struct{}{}, }) containers := []container.Container{ provider, consumer, } Expect(provider.ToRestart()).To(BeTrue()) Expect(consumer.ToRestart()).To(BeFalse()) actions.UpdateImplicitRestart(containers) Expect(containers[0].ToRestart()).To(BeTrue()) Expect(containers[1].ToRestart()).To(BeTrue()) }) }) When("container is not running", func() { BeforeEach(func() { client = CreateMockClient( &TestData{ //NameOfContainerToKeep: "test-container-02", Containers: []container.Container{ CreateMockContainerWithConfig( "test-container-02", "test-container-02", "fake-image2:latest", false, false, time.Now(), &dockerContainer.Config{ Labels: map[string]string{ "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout": "190", "com.centurylinklabs.watchtower.lifecycle.pre-update": "/PreUpdateReturn1.sh", }, ExposedPorts: map[nat.Port]struct{}{}, }), }, }, false, false, ) }) It("skip running preupdate", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true, LifecycleHooks: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1)) }) }) When("container is restarting", func() { BeforeEach(func() { client = CreateMockClient( &TestData{ //NameOfContainerToKeep: "test-container-02", Containers: []container.Container{ CreateMockContainerWithConfig( "test-container-02", "test-container-02", "fake-image2:latest", false, true, time.Now(), &dockerContainer.Config{ Labels: map[string]string{ "com.centurylinklabs.watchtower.lifecycle.pre-update-timeout": "190", "com.centurylinklabs.watchtower.lifecycle.pre-update": "/PreUpdateReturn1.sh", }, ExposedPorts: map[nat.Port]struct{}{}, }), }, }, false, false, ) }) It("skip running preupdate", func() { _, err := actions.Update(client, types.UpdateParams{Cleanup: true, LifecycleHooks: true}) Expect(err).NotTo(HaveOccurred()) Expect(client.TestData.TriedToRemoveImageCount).To(Equal(1)) }) }) }) })