1package persistence
2
3import (
4 "context"
5 "os"
6 "path/filepath"
7 "testing"
8 "time"
9)
10
11func TestFileRepository_NewFileRepository(t *testing.T) {
12 tmpDir := t.TempDir()
13
14 repo, err := NewFileRepository(tmpDir)
15 if err != nil {
16 t.Fatalf("expected no error, got %v", err)
17 }
18
19 if repo == nil {
20 t.Fatal("expected non-nil repository")
21 }
22
23 if repo.basePath != tmpDir {
24 t.Errorf("expected basePath %s, got %s", tmpDir, repo.basePath)
25 }
26}
27
28func TestFileRepository_NewFileRepository_CreatesDirectory(t *testing.T) {
29 tmpDir := t.TempDir()
30 nestedPath := filepath.Join(tmpDir, "nested", "path")
31
32 repo, err := NewFileRepository(nestedPath)
33 if err != nil {
34 t.Fatalf("expected no error, got %v", err)
35 }
36
37 if repo == nil {
38 t.Fatal("expected non-nil repository")
39 }
40
41 // Verify directory was created
42 info, err := os.Stat(nestedPath)
43 if err != nil {
44 t.Fatalf("expected directory to exist: %v", err)
45 }
46
47 if !info.IsDir() {
48 t.Error("expected directory")
49 }
50}
51
52func TestFileRepository_Save_Success(t *testing.T) {
53 tmpDir := t.TempDir()
54 repo, _ := NewFileRepository(tmpDir)
55
56 ctx := context.Background()
57 state := "test installation state"
58
59 err := repo.Save(ctx, "install-001", state)
60 if err != nil {
61 t.Fatalf("expected no error, got %v", err)
62 }
63
64 // Verify file was created
65 filePath := filepath.Join(tmpDir, "install-001.state")
66 if _, err := os.Stat(filePath); os.IsNotExist(err) {
67 t.Error("expected state file to be created")
68 }
69}
70
71func TestFileRepository_Save_Content(t *testing.T) {
72 tmpDir := t.TempDir()
73 repo, _ := NewFileRepository(tmpDir)
74
75 ctx := context.Background()
76 state := "test installation state with content"
77
78 if err := repo.Save(ctx, "install-001", state); err != nil {
79 t.Fatalf("expected no error, got %v", err)
80 }
81
82 // Verify file content
83 filePath := filepath.Join(tmpDir, "install-001.state")
84 content, _ := os.ReadFile(filePath)
85
86 if string(content) != state {
87 t.Errorf("expected %s, got %s", state, string(content))
88 }
89}
90
91func TestFileRepository_Save_Overwrite(t *testing.T) {
92 tmpDir := t.TempDir()
93 repo, _ := NewFileRepository(tmpDir)
94
95 ctx := context.Background()
96
97 // Save first state
98 if err := repo.Save(ctx, "install-001", "first state"); err != nil {
99 t.Fatalf("expected no error, got %v", err)
100 }
101
102 // Overwrite with second state
103 secondState := "second state"
104 if err := repo.Save(ctx, "install-001", secondState); err != nil {
105 t.Fatalf("expected no error, got %v", err)
106 }
107
108 // Verify file content is updated
109 filePath := filepath.Join(tmpDir, "install-001.state")
110 content, _ := os.ReadFile(filePath)
111
112 if string(content) != secondState {
113 t.Errorf("expected %s, got %s", secondState, string(content))
114 }
115}
116
117func TestFileRepository_Load_Success(t *testing.T) {
118 tmpDir := t.TempDir()
119 repo, _ := NewFileRepository(tmpDir)
120
121 // Save first
122 ctx := context.Background()
123 state := "test installation state"
124 if err := repo.Save(ctx, "install-001", state); err != nil {
125 t.Fatalf("expected no error, got %v", err)
126 }
127
128 // Load
129 loaded, err := repo.Load(ctx, "install-001")
130 if err != nil {
131 t.Fatalf("expected no error, got %v", err)
132 }
133
134 if loaded != state {
135 t.Errorf("expected %s, got %s", state, loaded)
136 }
137}
138
139func TestFileRepository_Load_NotFound(t *testing.T) {
140 tmpDir := t.TempDir()
141 repo, _ := NewFileRepository(tmpDir)
142
143 ctx := context.Background()
144 _, err := repo.Load(ctx, "nonexistent")
145
146 if err == nil {
147 t.Fatal("expected error for nonexistent installation")
148 }
149}
150
151func TestFileRepository_Exists_True(t *testing.T) {
152 tmpDir := t.TempDir()
153 repo, _ := NewFileRepository(tmpDir)
154
155 // Save first
156 ctx := context.Background()
157 if err := repo.Save(ctx, "install-001", "state"); err != nil {
158 t.Fatalf("expected no error, got %v", err)
159 }
160
161 // Check exists
162 exists, err := repo.Exists(ctx, "install-001")
163 if err != nil {
164 t.Fatalf("expected no error, got %v", err)
165 }
166
167 if !exists {
168 t.Error("expected installation to exist")
169 }
170}
171
172func TestFileRepository_Exists_False(t *testing.T) {
173 tmpDir := t.TempDir()
174 repo, _ := NewFileRepository(tmpDir)
175
176 ctx := context.Background()
177 exists, err := repo.Exists(ctx, "nonexistent")
178
179 if err != nil {
180 t.Fatalf("expected no error, got %v", err)
181 }
182
183 if exists {
184 t.Error("expected installation to not exist")
185 }
186}
187
188func TestFileRepository_Save_ContextCancelled(t *testing.T) {
189 tmpDir := t.TempDir()
190 repo, _ := NewFileRepository(tmpDir)
191
192 ctx, cancel := context.WithCancel(context.Background())
193 cancel()
194
195 err := repo.Save(ctx, "install-001", "state")
196 if err == nil {
197 t.Fatal("expected error due to context cancellation")
198 }
199}
200
201func TestFileRepository_Load_ContextCancelled(t *testing.T) {
202 tmpDir := t.TempDir()
203 repo, _ := NewFileRepository(tmpDir)
204
205 // Save first
206 ctx := context.Background()
207 if err := repo.Save(ctx, "install-001", "state"); err != nil {
208 t.Fatalf("expected no error, got %v", err)
209 }
210
211 // Load with cancelled context
212 ctx2, cancel := context.WithCancel(context.Background())
213 cancel()
214
215 _, err := repo.Load(ctx2, "install-001")
216 if err == nil {
217 t.Fatal("expected error due to context cancellation")
218 }
219}
220
221func TestFileRepository_Exists_ContextCancelled(t *testing.T) {
222 tmpDir := t.TempDir()
223 repo, _ := NewFileRepository(tmpDir)
224
225 ctx, cancel := context.WithCancel(context.Background())
226 cancel()
227
228 _, err := repo.Exists(ctx, "install-001")
229 if err == nil {
230 t.Fatal("expected error due to context cancellation")
231 }
232}
233
234func TestFileRepository_MultipleInstallations(t *testing.T) {
235 tmpDir := t.TempDir()
236 repo, _ := NewFileRepository(tmpDir)
237
238 ctx := context.Background()
239
240 // Save multiple installations
241 if err := repo.Save(ctx, "install-001", "state 1"); err != nil {
242 t.Fatalf("expected no error, got %v", err)
243 }
244 if err := repo.Save(ctx, "install-002", "state 2"); err != nil {
245 t.Fatalf("expected no error, got %v", err)
246 }
247 if err := repo.Save(ctx, "install-003", "state 3"); err != nil {
248 t.Fatalf("expected no error, got %v", err)
249 }
250
251 // Load each one
252 state1, _ := repo.Load(ctx, "install-001")
253 state2, _ := repo.Load(ctx, "install-002")
254 state3, _ := repo.Load(ctx, "install-003")
255
256 if state1 != "state 1" {
257 t.Errorf("expected 'state 1', got %s", state1)
258 }
259 if state2 != "state 2" {
260 t.Errorf("expected 'state 2', got %s", state2)
261 }
262 if state3 != "state 3" {
263 t.Errorf("expected 'state 3', got %s", state3)
264 }
265}
266
267func TestFileRepository_Save_ContextTimeout(t *testing.T) {
268 tmpDir := t.TempDir()
269 repo, _ := NewFileRepository(tmpDir)
270
271 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
272 defer cancel()
273
274 // Give it time to timeout
275 time.Sleep(10 * time.Millisecond)
276
277 err := repo.Save(ctx, "install-001", "state")
278 if err == nil {
279 t.Fatal("expected error due to context timeout")
280 }
281}