1package health
2
3import (
4 "context"
5 "errors"
6 "testing"
7
8 "github.com/bnema/zerowrap"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/mock"
11
12 inmocks "github.com/bnema/gordon/internal/boundaries/in/mocks"
13 outmocks "github.com/bnema/gordon/internal/boundaries/out/mocks"
14 "github.com/bnema/gordon/internal/domain"
15)
16
17func testLogger() zerowrap.Logger {
18 return zerowrap.Default()
19}
20
21func testActive() domain.AppActive {
22 return domain.AppActive{
23 App: "blog",
24 Services: map[string]domain.AppEffectiveService{
25 "web": {
26 EffectiveRevision: "rev-1",
27 Image: "img:1",
28 Container: "c-web",
29 BackendBinds: map[int]int{8080: 18080},
30 Spec: domain.AppService{
31 HTTP: []domain.AppHTTPInterface{{Host: "blog.example.com", Port: 8080, TLS: "auto"}},
32 },
33 },
34 },
35 }
36}
37
38func TestService_CheckAllRoutes_Healthy(t *testing.T) {
39 state := outmocks.NewMockAppState(t)
40 runtime := outmocks.NewMockContainerRuntime(t)
41 prober := inmocks.NewMockHTTPProber(t)
42
43 state.EXPECT().ListApps(mock.Anything).Return([]string{"blog"}, nil)
44 state.EXPECT().LoadIntent(mock.Anything, "blog").Return(domain.AppStopIntent{App: "blog"}, nil)
45 state.EXPECT().LoadActive(mock.Anything, "blog").Return(testActive(), true, nil)
46 runtime.EXPECT().IsContainerRunning(mock.Anything, "c-web").Return(true, nil)
47 prober.EXPECT().Probe(mock.Anything, "http://127.0.0.1:18080/").Return(200, int64(45), nil)
48
49 svc := NewService(state, runtime, prober, testLogger())
50
51 results := svc.CheckAllRoutes(context.Background())
52
53 assert.Len(t, results, 1)
54 health := results["blog.example.com"]
55 assert.Equal(t, "blog.example.com", health.Domain)
56 assert.Equal(t, "running", health.ContainerStatus)
57 assert.Equal(t, 200, health.HTTPStatus)
58 assert.Equal(t, int64(45), health.ResponseTimeMs)
59 assert.True(t, health.Healthy)
60 assert.Empty(t, health.Error)
61}
62
63func TestService_CheckAllRoutes_ContainerNotRunning(t *testing.T) {
64 state := outmocks.NewMockAppState(t)
65 runtime := outmocks.NewMockContainerRuntime(t)
66 prober := inmocks.NewMockHTTPProber(t)
67
68 state.EXPECT().ListApps(mock.Anything).Return([]string{"blog"}, nil)
69 state.EXPECT().LoadIntent(mock.Anything, "blog").Return(domain.AppStopIntent{App: "blog"}, nil)
70 state.EXPECT().LoadActive(mock.Anything, "blog").Return(testActive(), true, nil)
71 runtime.EXPECT().IsContainerRunning(mock.Anything, "c-web").Return(false, nil)
72
73 svc := NewService(state, runtime, prober, testLogger())
74
75 results := svc.CheckAllRoutes(context.Background())
76
77 assert.Len(t, results, 1)
78 assert.Equal(t, "not running", results["blog.example.com"].ContainerStatus)
79 assert.False(t, results["blog.example.com"].Healthy)
80}
81
82func TestService_CheckAllRoutes_ProbeFailure(t *testing.T) {
83 state := outmocks.NewMockAppState(t)
84 runtime := outmocks.NewMockContainerRuntime(t)
85 prober := inmocks.NewMockHTTPProber(t)
86
87 state.EXPECT().ListApps(mock.Anything).Return([]string{"blog"}, nil)
88 state.EXPECT().LoadIntent(mock.Anything, "blog").Return(domain.AppStopIntent{App: "blog"}, nil)
89 state.EXPECT().LoadActive(mock.Anything, "blog").Return(testActive(), true, nil)
90 runtime.EXPECT().IsContainerRunning(mock.Anything, "c-web").Return(true, nil)
91 prober.EXPECT().Probe(mock.Anything, "http://127.0.0.1:18080/").Return(0, int64(0), errors.New("connection refused"))
92
93 svc := NewService(state, runtime, prober, testLogger())
94
95 results := svc.CheckAllRoutes(context.Background())
96
97 assert.Len(t, results, 1)
98 assert.Equal(t, "running", results["blog.example.com"].ContainerStatus)
99 assert.False(t, results["blog.example.com"].Healthy)
100 assert.Equal(t, "connection refused", results["blog.example.com"].Error)
101}
102
103func TestService_CheckAllRoutes_StoppedIntentSkipped(t *testing.T) {
104 state := outmocks.NewMockAppState(t)
105 runtime := outmocks.NewMockContainerRuntime(t)
106 prober := inmocks.NewMockHTTPProber(t)
107
108 state.EXPECT().ListApps(mock.Anything).Return([]string{"blog"}, nil)
109 state.EXPECT().LoadIntent(mock.Anything, "blog").Return(domain.AppStopIntent{App: "blog", Stopped: true}, nil)
110
111 svc := NewService(state, runtime, prober, testLogger())
112
113 results := svc.CheckAllRoutes(context.Background())
114
115 assert.Empty(t, results)
116}
117
118func TestService_CheckAllRoutes_NoApps(t *testing.T) {
119 state := outmocks.NewMockAppState(t)
120 runtime := outmocks.NewMockContainerRuntime(t)
121 prober := inmocks.NewMockHTTPProber(t)
122
123 state.EXPECT().ListApps(mock.Anything).Return(nil, nil)
124
125 svc := NewService(state, runtime, prober, testLogger())
126
127 results := svc.CheckAllRoutes(context.Background())
128
129 assert.Empty(t, results)
130}