@@ -113,3 +113,209 @@ describe("PostgreSqlContainer", { timeout: 180_000 }, () => {
113113 await expect ( ( ) => container . start ( ) ) . rejects . toThrow ( ) ;
114114 } ) ;
115115} ) ;
116+
117+ describe ( "PostgreSqlContainer snapshot and restore" , { timeout : 180_000 } , ( ) => {
118+ // createAndRestoreFromSnapshot {
119+ it ( "should create and restore from snapshot" , async ( ) => {
120+ const container = await new PostgreSqlContainer ( ) . start ( ) ;
121+
122+ // Connect to the database
123+ let client = new Client ( {
124+ connectionString : container . getConnectionUri ( ) ,
125+ } ) ;
126+ await client . connect ( ) ;
127+
128+ // Create some test data
129+ await client . query ( "CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)" ) ;
130+ await client . query ( "INSERT INTO test_table (name) VALUES ('initial data')" ) ;
131+
132+ // Close connection before snapshot (otherwise we'll get an error because user is already connected)
133+ await client . end ( ) ;
134+
135+ // Take a snapshot
136+ await container . snapshot ( ) ;
137+
138+ // Reconnect to database
139+ client = new Client ( {
140+ connectionString : container . getConnectionUri ( ) ,
141+ } ) ;
142+ await client . connect ( ) ;
143+
144+ // Modify the database
145+ await client . query ( "INSERT INTO test_table (name) VALUES ('data after snapshot')" ) ;
146+
147+ // Verify both records exist
148+ let result = await client . query ( "SELECT * FROM test_table ORDER BY id" ) ;
149+ expect ( result . rows ) . toHaveLength ( 2 ) ;
150+ expect ( result . rows [ 0 ] . name ) . toEqual ( "initial data" ) ;
151+ expect ( result . rows [ 1 ] . name ) . toEqual ( "data after snapshot" ) ;
152+
153+ // Close connection before restore (same reason as above)
154+ await client . end ( ) ;
155+
156+ // Restore to the snapshot
157+ await container . restoreSnapshot ( ) ;
158+
159+ // Reconnect to database
160+ client = new Client ( {
161+ connectionString : container . getConnectionUri ( ) ,
162+ } ) ;
163+ await client . connect ( ) ;
164+
165+ // Verify only the initial data exists after restore
166+ result = await client . query ( "SELECT * FROM test_table ORDER BY id" ) ;
167+ expect ( result . rows ) . toHaveLength ( 1 ) ;
168+ expect ( result . rows [ 0 ] . name ) . toEqual ( "initial data" ) ;
169+
170+ await client . end ( ) ;
171+ await container . stop ( ) ;
172+ } ) ;
173+ // }
174+
175+ it ( "should use custom snapshot name" , async ( ) => {
176+ const container = await new PostgreSqlContainer ( ) . start ( ) ;
177+ const customSnapshotName = "my_custom_snapshot" ;
178+
179+ // Connect to the database
180+ let client = new Client ( {
181+ connectionString : container . getConnectionUri ( ) ,
182+ } ) ;
183+ await client . connect ( ) ;
184+
185+ // Create a test table and insert data
186+ await client . query ( "CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)" ) ;
187+ await client . query ( "INSERT INTO test_table (name) VALUES ('initial data')" ) ;
188+
189+ // Close connection before snapshot
190+ await client . end ( ) ;
191+
192+ // Take a snapshot with custom name
193+ await container . snapshot ( customSnapshotName ) ;
194+
195+ // Reconnect to database
196+ client = new Client ( {
197+ connectionString : container . getConnectionUri ( ) ,
198+ } ) ;
199+ await client . connect ( ) ;
200+
201+ // Modify the database
202+ await client . query ( "INSERT INTO test_table (name) VALUES ('data after snapshot')" ) ;
203+
204+ // Close connection before restore
205+ await client . end ( ) ;
206+
207+ // Restore using the custom snapshot name
208+ await container . restoreSnapshot ( customSnapshotName ) ;
209+
210+ // Reconnect to database
211+ client = new Client ( {
212+ connectionString : container . getConnectionUri ( ) ,
213+ } ) ;
214+ await client . connect ( ) ;
215+
216+ // Verify only the initial data exists after restore
217+ const result = await client . query ( "SELECT * FROM test_table ORDER BY id" ) ;
218+ expect ( result . rows ) . toHaveLength ( 1 ) ;
219+ expect ( result . rows [ 0 ] . name ) . toEqual ( "initial data" ) ;
220+
221+ await client . end ( ) ;
222+ await container . stop ( ) ;
223+ } ) ;
224+
225+ it ( "should handle multiple snapshots" , async ( ) => {
226+ const container = await new PostgreSqlContainer ( ) . start ( ) ;
227+
228+ // Connect to the database
229+ let client = new Client ( {
230+ connectionString : container . getConnectionUri ( ) ,
231+ } ) ;
232+ await client . connect ( ) ;
233+
234+ // Create a test table
235+ await client . query ( "CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)" ) ;
236+
237+ // Close connection before snapshot
238+ await client . end ( ) ;
239+
240+ // Take first snapshot with empty table
241+ await container . snapshot ( "snapshot1" ) ;
242+
243+ // Reconnect to database
244+ client = new Client ( {
245+ connectionString : container . getConnectionUri ( ) ,
246+ } ) ;
247+ await client . connect ( ) ;
248+
249+ // Add first record
250+ await client . query ( "INSERT INTO test_table (name) VALUES ('data for snapshot 2')" ) ;
251+
252+ // Close connection before snapshot
253+ await client . end ( ) ;
254+
255+ // Take second snapshot with one record
256+ await container . snapshot ( "snapshot2" ) ;
257+
258+ // Reconnect to database
259+ client = new Client ( {
260+ connectionString : container . getConnectionUri ( ) ,
261+ } ) ;
262+ await client . connect ( ) ;
263+
264+ // Add second record
265+ await client . query ( "INSERT INTO test_table (name) VALUES ('data after snapshots')" ) ;
266+
267+ // Verify we have two records
268+ let result = await client . query ( "SELECT COUNT(*) as count FROM test_table" ) ;
269+ expect ( result . rows [ 0 ] . count ) . toEqual ( "2" ) ;
270+
271+ // Close connection before restore
272+ await client . end ( ) ;
273+
274+ // Restore to first snapshot (empty table)
275+ await container . restoreSnapshot ( "snapshot1" ) ;
276+
277+ // Reconnect to database
278+ client = new Client ( {
279+ connectionString : container . getConnectionUri ( ) ,
280+ } ) ;
281+ await client . connect ( ) ;
282+
283+ // Verify table is empty
284+ result = await client . query ( "SELECT COUNT(*) as count FROM test_table" ) ;
285+ expect ( result . rows [ 0 ] . count ) . toEqual ( "0" ) ;
286+
287+ // Close connection before restore
288+ await client . end ( ) ;
289+
290+ // Restore to second snapshot (one record)
291+ await container . restoreSnapshot ( "snapshot2" ) ;
292+
293+ // Reconnect to database
294+ client = new Client ( {
295+ connectionString : container . getConnectionUri ( ) ,
296+ } ) ;
297+ await client . connect ( ) ;
298+
299+ // Verify we have one record
300+ result = await client . query ( "SELECT * FROM test_table" ) ;
301+ expect ( result . rows ) . toHaveLength ( 1 ) ;
302+ expect ( result . rows [ 0 ] . name ) . toEqual ( "data for snapshot 2" ) ;
303+
304+ await client . end ( ) ;
305+ await container . stop ( ) ;
306+ } ) ;
307+
308+ it ( "should throw an error when trying to snapshot postgres system database" , async ( ) => {
309+ const container = await new PostgreSqlContainer ( ) . withDatabase ( "postgres" ) . start ( ) ;
310+
311+ await expect ( container . snapshot ( ) ) . rejects . toThrow (
312+ "Snapshot feature is not supported when using the postgres system database"
313+ ) ;
314+
315+ await expect ( container . restoreSnapshot ( ) ) . rejects . toThrow (
316+ "Snapshot feature is not supported when using the postgres system database"
317+ ) ;
318+
319+ await container . stop ( ) ;
320+ } ) ;
321+ } ) ;
0 commit comments