1package preview
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10
11 "github.com/bnema/gordon/internal/domain"
12)
13
14type fakeStore struct {
15 previews []domain.PreviewRoute
16}
17
18func (f *fakeStore) Load(_ context.Context) ([]domain.PreviewRoute, error) {
19 return f.previews, nil
20}
21func (f *fakeStore) Save(_ context.Context, p []domain.PreviewRoute) error {
22 f.previews = p
23 return nil
24}
25
26func TestPreviewService_Add(t *testing.T) {
27 store := &fakeStore{}
28 svc := NewService(store, 48*time.Hour)
29
30 p := domain.PreviewRoute{
31 Domain: "myapp--feat.example.com",
32 Name: "feat",
33 BaseRoute: "myapp.example.com",
34 Image: "myapp:preview-feat",
35 }
36 err := svc.Add(t.Context(), p)
37 require.NoError(t, err)
38
39 all, err := svc.List(t.Context())
40 require.NoError(t, err)
41 assert.Len(t, all, 1)
42 assert.Equal(t, "feat", all[0].Name)
43}
44
45func TestPreviewService_Delete(t *testing.T) {
46 store := &fakeStore{
47 previews: []domain.PreviewRoute{
48 {Name: "feat", Domain: "myapp--feat.example.com"},
49 },
50 }
51 svc := NewService(store, 48*time.Hour)
52 require.NoError(t, svc.Load(t.Context()))
53
54 err := svc.Delete(t.Context(), "feat")
55 require.NoError(t, err)
56
57 all, err := svc.List(t.Context())
58 require.NoError(t, err)
59 assert.Empty(t, all)
60}
61
62func TestPreviewService_Get(t *testing.T) {
63 store := &fakeStore{
64 previews: []domain.PreviewRoute{
65 {Name: "feat", Domain: "myapp--feat.example.com"},
66 },
67 }
68 svc := NewService(store, 48*time.Hour)
69 require.NoError(t, svc.Load(t.Context()))
70
71 p, err := svc.Get(t.Context(), "feat")
72 require.NoError(t, err)
73 assert.Equal(t, "myapp--feat.example.com", p.Domain)
74
75 _, err = svc.Get(t.Context(), "nonexistent")
76 assert.Error(t, err)
77}
78
79func TestPreviewService_Extend(t *testing.T) {
80 now := time.Now()
81 store := &fakeStore{
82 previews: []domain.PreviewRoute{
83 {Name: "feat", ExpiresAt: now.Add(1 * time.Hour)},
84 },
85 }
86 svc := NewService(store, 48*time.Hour)
87 require.NoError(t, svc.Load(t.Context()))
88
89 err := svc.Extend(t.Context(), "feat", 24*time.Hour)
90 require.NoError(t, err)
91
92 p, err := svc.Get(t.Context(), "feat")
93 require.NoError(t, err)
94 assert.True(t, p.ExpiresAt.After(now.Add(23*time.Hour)))
95}
96
97func TestPreviewService_GetExpired(t *testing.T) {
98 store := &fakeStore{
99 previews: []domain.PreviewRoute{
100 {Name: "expired", ExpiresAt: time.Now().Add(-1 * time.Hour)},
101 {Name: "active", ExpiresAt: time.Now().Add(1 * time.Hour)},
102 },
103 }
104 svc := NewService(store, 48*time.Hour)
105 require.NoError(t, svc.Load(t.Context()))
106
107 expired := svc.GetExpired()
108 assert.Len(t, expired, 1)
109 assert.Equal(t, "expired", expired[0].Name)
110}
111
112func TestPreviewService_Update(t *testing.T) {
113 store := &fakeStore{
114 previews: []domain.PreviewRoute{
115 {Name: "feat", Domain: "myapp--feat.example.com", Status: domain.PreviewStatusDeploying},
116 },
117 }
118 svc := NewService(store, 48*time.Hour)
119 require.NoError(t, svc.Load(t.Context()))
120
121 updated := domain.PreviewRoute{
122 Name: "feat",
123 Domain: "myapp--feat.example.com",
124 Status: domain.PreviewStatusRunning,
125 Containers: []string{"gordon-myapp--feat.example.com"},
126 }
127 err := svc.Update(t.Context(), updated)
128 require.NoError(t, err)
129
130 p, err := svc.Get(t.Context(), "feat")
131 require.NoError(t, err)
132 assert.Equal(t, domain.PreviewStatusRunning, p.Status)
133 assert.Equal(t, []string{"gordon-myapp--feat.example.com"}, p.Containers)
134}
135
136func TestPreviewService_Update_NotFound(t *testing.T) {
137 store := &fakeStore{}
138 svc := NewService(store, 48*time.Hour)
139
140 err := svc.Update(t.Context(), domain.PreviewRoute{Name: "nonexistent"})
141 assert.ErrorIs(t, err, domain.ErrPreviewNotFound)
142}