1package deployment
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 "github.com/bnema/zerowrap"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/mock"
11 "github.com/stretchr/testify/require"
12
13 outmocks "github.com/bnema/gordon/internal/boundaries/out/mocks"
14 "github.com/bnema/gordon/internal/domain"
15)
16
17// TestRetireContainer_ForceSkipsTheGracePeriod proves a never-published
18// candidate is removed without waiting for a grace period.
19func TestRetireContainer_ForceSkipsTheGracePeriod(t *testing.T) {
20 ctx := context.Background()
21 state := outmocks.NewMockAppState(t)
22 runtime := outmocks.NewMockContainerRuntime(t)
23 runtime.EXPECT().RemoveContainer(mock.Anything, "c-candidate", true).Return(nil).Once()
24 state.EXPECT().ReleaseBackendBinds(mock.Anything, "blog", "c-candidate").Return(nil).Once()
25
26 svc := NewService(Deps{State: state, Runtime: runtime}, zerowrap.Default())
27 retired := svc.retireContainer(ctx, "blog", retireOptions{Service: "web", Force: true}, "c-candidate")
28 assert.True(t, retired.Gone)
29 assert.Empty(t, retired.Warnings)
30 runtime.AssertNotCalled(t, "StopContainer", mock.Anything, mock.Anything, mock.Anything)
31}
32
33// TestRetireContainer_UnconfirmedRemovalKeepsClaims proves a container the
34// runtime would not remove keeps its backend claims and its recovery
35// inhibition, and reports a bounded warning instead of a success.
36func TestRetireContainer_UnconfirmedRemovalKeepsClaims(t *testing.T) {
37 ctx := context.Background()
38 state := outmocks.NewMockAppState(t)
39 runtime := outmocks.NewMockContainerRuntime(t)
40 runtime.EXPECT().StopContainer(mock.Anything, "c-1", 5*time.Second).Return(nil).Once()
41 runtime.EXPECT().RemoveContainer(mock.Anything, "c-1", false).Return(assert.AnError).Once()
42
43 svc := NewService(Deps{State: state, Runtime: runtime}, zerowrap.Default())
44 retired := svc.retireContainer(ctx, "blog", retireOptions{
45 Service: "web", Grace: 5 * time.Second, ClearInhibition: true,
46 }, "c-1")
47
48 assert.False(t, retired.Gone)
49 require.Len(t, retired.Warnings, 1)
50 assert.Equal(t, "c-1", retired.Warnings[0].Leftover)
51 assert.Contains(t, retired.Warnings[0].Detail, "remove")
52 state.AssertNotCalled(t, "ReleaseBackendBinds", mock.Anything, mock.Anything, mock.Anything)
53 state.AssertNotCalled(t, "ClearRecoveryInhibition", mock.Anything, mock.Anything, mock.Anything, mock.Anything)
54}
55
56// TestRetireContainer_ZeroGraceUsesTheAppDefault proves a zero grace is
57// never an immediate kill on an app path.
58func TestRetireContainer_ZeroGraceUsesTheAppDefault(t *testing.T) {
59 ctx := context.Background()
60 state := outmocks.NewMockAppState(t)
61 runtime := outmocks.NewMockContainerRuntime(t)
62 runtime.EXPECT().StopContainer(mock.Anything, "c-1", domain.AppDefaultStopGrace).Return(nil).Once()
63 runtime.EXPECT().RemoveContainer(mock.Anything, "c-1", false).Return(nil).Once()
64 state.EXPECT().ReleaseBackendBinds(mock.Anything, "blog", "c-1").Return(nil).Once()
65
66 svc := NewService(Deps{State: state, Runtime: runtime}, zerowrap.Default())
67 retired := svc.retireContainer(ctx, "blog", retireOptions{Service: "web"}, "c-1")
68 assert.True(t, retired.Gone)
69 assert.Empty(t, retired.Warnings)
70}