@@ -19,6 +19,7 @@ package archiver
1919
2020import (
2121 "os"
22+ "path/filepath"
2223 "strings"
2324
2425 pgbackrestApi "github.com/operasoftware/cnpg-plugin-pgbackrest/internal/pgbackrest/api"
@@ -75,3 +76,161 @@ var _ = Describe("pgbackrestWalArchiveOptions", func() {
7576 ))
7677 })
7778})
79+
80+ var _ = Describe ("GatherWALFilesToArchive" , func () {
81+ var tempPgData string
82+ var archiveStatusDir string
83+ var archiver * WALArchiver
84+
85+ BeforeEach (func (ctx SpecContext ) {
86+ var err error
87+
88+ tempPgData , err = os .MkdirTemp ("" , "pgdata-test-*" )
89+ Expect (err ).ToNot (HaveOccurred ())
90+
91+ // Archiver uses the env variable to determine directory root.
92+ os .Setenv ("PGDATA" , tempPgData )
93+
94+ archiveStatusDir = filepath .Join (tempPgData , "pg_wal" , "archive_status" )
95+ err = os .MkdirAll (archiveStatusDir , 0755 )
96+ Expect (err ).ToNot (HaveOccurred ())
97+
98+ tempEmptyWalArchivePath := filepath .Join (tempPgData , "empty-wal-archive" )
99+ _ , err = os .Create (tempEmptyWalArchivePath )
100+ Expect (err ).ToNot (HaveOccurred ())
101+
102+ archiver , err = New (ctx , nil , filepath .Join (tempPgData , "spool" ), tempPgData , tempEmptyWalArchivePath )
103+ Expect (err ).ToNot (HaveOccurred ())
104+ })
105+
106+ AfterEach (func () {
107+ // Clean up temp directory
108+ if tempPgData != "" {
109+ os .RemoveAll (tempPgData )
110+ }
111+ os .Unsetenv ("PGDATA" )
112+ })
113+
114+ // Helper function to create .ready files
115+ createReadyFile := func (walName string ) {
116+ path := filepath .Join (archiveStatusDir , walName + ".ready" )
117+ err := os .WriteFile (path , []byte {}, 0644 )
118+ Expect (err ).ToNot (HaveOccurred ())
119+ }
120+
121+ Context ("when parallel=1" , func () {
122+ It ("should gather only the requested file" , func (ctx SpecContext ) {
123+ // Create .ready files for multiple WAL files
124+ createReadyFile ("000000010000000000000001" )
125+ createReadyFile ("000000010000000000000002" )
126+ createReadyFile ("000000010000000000000003" )
127+
128+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/000000010000000000000001" , 1 )
129+
130+ Expect (walList ).To (ConsistOf ("pg_wal/000000010000000000000001" ))
131+ })
132+
133+ It ("should handle when no other .ready files exist" , func (ctx SpecContext ) {
134+ // Only create the requested file
135+ createReadyFile ("000000010000000000000001" )
136+
137+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/000000010000000000000001" , 1 )
138+
139+ Expect (walList ).To (ConsistOf ("pg_wal/000000010000000000000001" ))
140+ })
141+ })
142+
143+ Context ("when parallel>1" , func () {
144+ It ("should gather multiple files when parallel=4" , func (ctx SpecContext ) {
145+ // Create .ready files for multiple WAL files
146+ createReadyFile ("000000010000000000000001" )
147+ createReadyFile ("000000010000000000000002" )
148+ createReadyFile ("000000010000000000000003" )
149+ createReadyFile ("000000010000000000000004" )
150+
151+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/000000010000000000000001" , 4 )
152+
153+ Expect (walList ).To (ConsistOf (
154+ "pg_wal/000000010000000000000001" ,
155+ "pg_wal/000000010000000000000002" ,
156+ "pg_wal/000000010000000000000003" ,
157+ "pg_wal/000000010000000000000004" ,
158+ ))
159+ })
160+
161+ It ("should not exceed parallel limit even when more files are ready" , func (ctx SpecContext ) {
162+ // Create many .ready files
163+ for i := 1 ; i <= 10 ; i ++ {
164+ createReadyFile ("00000001000000000000000" + string (rune ('0' + i )))
165+ }
166+
167+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/000000010000000000000001" , 3 )
168+
169+ Expect (walList ).To (HaveLen (3 ))
170+ })
171+
172+ It ("should handle when fewer files exist than parallel limit" , func (ctx SpecContext ) {
173+ // Create only 2 .ready files but request parallel=5
174+ createReadyFile ("000000010000000000000001" )
175+ createReadyFile ("000000010000000000000002" )
176+
177+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/000000010000000000000001" , 5 )
178+
179+ // Should only get the files that exist
180+ Expect (walList ).To (ConsistOf (
181+ "pg_wal/000000010000000000000001" ,
182+ "pg_wal/000000010000000000000002" ,
183+ ))
184+ })
185+ })
186+
187+ Context ("edge cases" , func () {
188+ It ("should handle empty archive_status directory" , func (ctx SpecContext ) {
189+ // Don't create any .ready files
190+
191+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/000000010000000000000001" , 3 )
192+
193+ // Should still return the requested file
194+ Expect (walList ).To (ConsistOf ("pg_wal/000000010000000000000001" ))
195+ })
196+
197+ })
198+
199+ Context ("other files in directory" , func () {
200+ It ("should ignore non-.ready files in archive_status" , func (ctx SpecContext ) {
201+ // Create .ready files
202+ createReadyFile ("000000010000000000000001" )
203+ createReadyFile ("000000010000000000000002" )
204+
205+ // Create .done files (should be ignored)
206+ donePath := filepath .Join (archiveStatusDir , "000000010000000000000003.done" )
207+ err := os .WriteFile (donePath , []byte {}, 0644 )
208+ Expect (err ).ToNot (HaveOccurred ())
209+
210+ // Create a random file (should be ignored)
211+ randomPath := filepath .Join (archiveStatusDir , "random.txt" )
212+ err = os .WriteFile (randomPath , []byte {}, 0644 )
213+ Expect (err ).ToNot (HaveOccurred ())
214+
215+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/000000010000000000000001" , 5 )
216+
217+ // Should only get .ready files, not .done or other files
218+ Expect (walList ).To (ConsistOf (
219+ "pg_wal/000000010000000000000001" ,
220+ "pg_wal/000000010000000000000002" ,
221+ ))
222+ })
223+ It ("should handle timeline history files" , func (ctx SpecContext ) {
224+ // Create timeline history file
225+ createReadyFile ("00000002.history" )
226+ createReadyFile ("000000010000000000000001" )
227+
228+ walList := archiver .GatherWALFilesToArchive (ctx , "pg_wal/00000002.history" , 2 )
229+
230+ Expect (walList ).To (ConsistOf (
231+ "pg_wal/00000002.history" ,
232+ "pg_wal/000000010000000000000001" ,
233+ ))
234+ })
235+ })
236+ })
0 commit comments