@@ -93,4 +93,108 @@ var _ = Describe("Spool", func() {
9393 const walFile = "000000020000068A00000004"
9494 Expect (spool .FileName (walFile )).To (Equal (path .Join (tmpDir , walFile )))
9595 })
96+
97+ It ("returns temp file path with .tmp suffix" , func () {
98+ const walFile = "000000020000068A00000005"
99+ tempPath := spool .TempFileName (walFile )
100+ Expect (tempPath ).To (Equal (path .Join (tmpDir , walFile + ".tmp" )))
101+ })
102+
103+ It ("commits a temp file to its final location" , func () {
104+ const walFile = "000000020000068A00000006"
105+
106+ // Create a temp file with some content
107+ tempPath := spool .TempFileName (walFile )
108+ err := os .WriteFile (tempPath , []byte ("test content" ), 0o600 )
109+ Expect (err ).ToNot (HaveOccurred ())
110+
111+ // Temp file exists, final file does not
112+ Expect (fileutils .FileExists (tempPath )).To (BeTrue ())
113+ Expect (spool .Contains (walFile )).To (BeFalse ())
114+
115+ // Commit the file
116+ err = spool .Commit (walFile )
117+ Expect (err ).ToNot (HaveOccurred ())
118+
119+ // Now final file exists, temp file does not
120+ Expect (spool .Contains (walFile )).To (BeTrue ())
121+ tempExists , _ := fileutils .FileExists (tempPath )
122+ Expect (tempExists ).To (BeFalse ())
123+
124+ // Verify content was preserved
125+ content , err := os .ReadFile (spool .FileName (walFile ))
126+ Expect (err ).ToNot (HaveOccurred ())
127+ Expect (string (content )).To (Equal ("test content" ))
128+ })
129+
130+ It ("returns error when committing non-existent temp file" , func () {
131+ const walFile = "000000020000068A00000007"
132+
133+ err := spool .Commit (walFile )
134+ Expect (err ).To (HaveOccurred ())
135+ Expect (err .Error ()).To (ContainSubstring ("failed to commit WAL file" ))
136+ })
137+
138+ It ("cleans up temp files" , func () {
139+ const walFile = "000000020000068A00000008"
140+
141+ // Create a temp file
142+ tempPath := spool .TempFileName (walFile )
143+ err := os .WriteFile (tempPath , []byte ("test content" ), 0o600 )
144+ Expect (err ).ToNot (HaveOccurred ())
145+ Expect (fileutils .FileExists (tempPath )).To (BeTrue ())
146+
147+ // Clean it up
148+ spool .CleanupTemp (walFile )
149+
150+ // Temp file should be gone
151+ tempExists , _ := fileutils .FileExists (tempPath )
152+ Expect (tempExists ).To (BeFalse ())
153+ })
154+
155+ It ("cleanup is safe on non-existent temp file" , func () {
156+ const walFile = "000000020000068A00000009"
157+
158+ // This should not panic or error
159+ spool .CleanupTemp (walFile )
160+ })
161+
162+ // These two tests verify the race condition fix:
163+ // temp files (.tmp) must be invisible to Contains and MoveOut
164+
165+ It ("Contains does NOT see temp files" , func () {
166+ const walFile = "000000020000068A0000000A"
167+
168+ // Create a temp file (simulating an in-progress download)
169+ tempPath := spool .TempFileName (walFile )
170+ err := os .WriteFile (tempPath , []byte ("partial content" ), 0o600 )
171+ Expect (err ).ToNot (HaveOccurred ())
172+
173+ // Contains should return false - temp files are invisible
174+ Expect (spool .Contains (walFile )).To (BeFalse ())
175+
176+ // Clean up
177+ spool .CleanupTemp (walFile )
178+ })
179+
180+ It ("MoveOut does NOT see temp files" , func () {
181+ const walFile = "000000020000068A0000000B"
182+
183+ // Create a temp file (simulating an in-progress download)
184+ tempPath := spool .TempFileName (walFile )
185+ err := os .WriteFile (tempPath , []byte ("partial content" ), 0o600 )
186+ Expect (err ).ToNot (HaveOccurred ())
187+
188+ // MoveOut should fail with ErrorNonExistentFile - temp files are invisible
189+ destinationPath := path .Join (tmpDir2 , "testFile" )
190+ err = spool .MoveOut (walFile , destinationPath )
191+ Expect (err ).To (Equal (ErrorNonExistentFile ))
192+
193+ // Destination should not exist
194+ destExists , _ := fileutils .FileExists (destinationPath )
195+ Expect (destExists ).To (BeFalse ())
196+
197+ // Clean up
198+ spool .CleanupTemp (walFile )
199+ })
96200})
0 commit comments