github.com/tuhaihe/gpbackup@v1.0.3/integration/snapshot_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 6 "github.com/tuhaihe/gpbackup/backup" 7 "github.com/tuhaihe/gpbackup/testutils" 8 9 . "github.com/onsi/ginkgo/v2" 10 . "github.com/onsi/gomega" 11 ) 12 13 var _ = Describe("synchronized snapshot integration tests", func() { 14 BeforeEach(func() { 15 if false { 16 Skip("snapshot feature not supported") 17 } 18 }) 19 Describe("GetSynchronizedSnapshot", func() { 20 It("returns a correctly formatted snapshot identifier", func() { 21 snapshotId, err := backup.GetSynchronizedSnapshot(connectionPool) 22 Expect(err).ToNot(HaveOccurred()) 23 Expect(snapshotId).ToNot(BeEmpty()) 24 Expect(snapshotId).To(MatchRegexp("[0-9a-fA-F]+-\\d")) 25 }) 26 It("returns a valid snapshot identifier that can be used to set a snapshot", func() { 27 exportConn := testutils.SetupTestDbConn("testdb") 28 importConn := testutils.SetupTestDbConn("testdb") 29 exportConn.MustBegin() 30 importConn.MustBegin() 31 snapshotId, err := backup.GetSynchronizedSnapshot(exportConn) 32 Expect(err).ToNot(HaveOccurred()) 33 34 _, err = importConn.Exec(fmt.Sprintf("SET TRANSACTION SNAPSHOT '%s'", snapshotId), 0) 35 Expect(err).ToNot(HaveOccurred()) 36 37 exportConn.MustCommit() 38 importConn.MustCommit() 39 exportConn.Close() 40 importConn.Close() 41 }) 42 }) 43 Describe("SetSynchronizedSnapshot", func() { 44 It("sets snapshot to snapshotId", func() { 45 var snapshotId string 46 exportConn := testutils.SetupTestDbConn("testdb") 47 importConn := testutils.SetupTestDbConn("testdb") 48 exportConn.MustBegin() 49 importConn.MustBegin() 50 err := exportConn.Get(&snapshotId, "SELECT pg_catalog.pg_export_snapshot()", 0) 51 Expect(err).ToNot(HaveOccurred()) 52 53 err = backup.SetSynchronizedSnapshot(importConn, 0, snapshotId) 54 Expect(err).ToNot(HaveOccurred()) 55 56 exportConn.MustCommit() 57 importConn.MustCommit() 58 exportConn.Close() 59 importConn.Close() 60 }) 61 }) 62 Describe("functionality tests", func() { 63 BeforeEach(func() { 64 connectionPool.Exec("CREATE TABLE IF NOT EXISTS snapshot_test (a int)") 65 connectionPool.Exec("TRUNCATE TABLE snapshot_test") 66 }) 67 It("handles concurrent insert", func() { 68 query := "SELECT count(*) FROM snapshot_test" 69 var result int 70 exportConn := testutils.SetupTestDbConn("testdb") 71 importConn := testutils.SetupTestDbConn("testdb") 72 connectionPool.Exec("INSERT INTO snapshot_test values(1)") 73 74 exportConn.MustBegin(0) 75 snapshotId, err := backup.GetSynchronizedSnapshot(exportConn) 76 Expect(err).ToNot(HaveOccurred()) 77 // External command inserts row 78 connectionPool.Exec("INSERT INTO snapshot_test values(2)") 79 connectionPool.Get(&result, query) 80 Expect(result).To(Equal(2)) 81 82 // export should not see inserted row 83 err = exportConn.Get(&result, query) 84 Expect(err).ToNot(HaveOccurred()) 85 Expect(result).To(Equal(1)) 86 87 // import should see inserted row 88 err = importConn.Get(&result, query) 89 Expect(err).ToNot(HaveOccurred()) 90 Expect(result).To(Equal(2)) 91 92 importConn.MustBegin(0) 93 err = backup.SetSynchronizedSnapshot(importConn, 0, snapshotId) 94 // Should see snapshot with 1 row 95 Expect(err).ToNot(HaveOccurred()) 96 importConn.Get(&result, query) 97 Expect(result).To(Equal(1)) 98 99 // after commits, inserted row is visible to both conns 100 err = exportConn.Commit(0) 101 Expect(err).ToNot(HaveOccurred()) 102 err = importConn.Commit(0) 103 Expect(err).ToNot(HaveOccurred()) 104 105 err = exportConn.Get(&result, query) 106 Expect(err).ToNot(HaveOccurred()) 107 Expect(result).To(Equal(2)) 108 109 err = importConn.Get(&result, query) 110 Expect(err).ToNot(HaveOccurred()) 111 Expect(result).To(Equal(2)) 112 113 exportConn.Close() 114 importConn.Close() 115 }) 116 It("handles concurrent update", func() { 117 var result int 118 query := "SELECT count(*) from snapshot_test WHERE a=99" 119 exportConn := testutils.SetupTestDbConn("testdb") 120 importConn := testutils.SetupTestDbConn("testdb") 121 connectionPool.Exec("INSERT INTO snapshot_test SELECT a FROM generate_series(1,5) a") 122 123 // export the snapshot 124 exportConn.MustBegin(0) 125 snapshotId, err := backup.GetSynchronizedSnapshot(exportConn) 126 Expect(err).ToNot(HaveOccurred()) 127 Expect(snapshotId).ToNot(BeEmpty()) 128 129 // external command updates row 130 _, err = connectionPool.Exec("UPDATE snapshot_test SET a=99 WHERE a=1") 131 Expect(err).ToNot(HaveOccurred()) 132 err = importConn.Get(&result, query) 133 Expect(err).ToNot(HaveOccurred()) 134 Expect(result).To(Equal(1)) 135 136 // export should not see updated row 137 err = exportConn.Get(&result, query) 138 Expect(err).ToNot(HaveOccurred()) 139 Expect(result).To(Equal(0)) 140 141 // import should see updated row 142 err = importConn.Get(&result, query) 143 Expect(err).ToNot(HaveOccurred()) 144 Expect(result).To(Equal(1)) 145 146 // now set snapshot, import should not see updated row 147 importConn.MustBegin(0) 148 err = backup.SetSynchronizedSnapshot(importConn, 0, snapshotId) 149 Expect(err).ToNot(HaveOccurred()) 150 err = importConn.Get(&result, query) 151 Expect(err).ToNot(HaveOccurred()) 152 Expect(result).To(Equal(0)) 153 154 // after commits, updated row is visible to both conns 155 err = exportConn.Commit(0) 156 Expect(err).ToNot(HaveOccurred()) 157 err = importConn.Commit(0) 158 Expect(err).ToNot(HaveOccurred()) 159 160 err = exportConn.Get(&result, query) 161 Expect(err).ToNot(HaveOccurred()) 162 Expect(result).To(Equal(1)) 163 164 err = importConn.Get(&result, query) 165 Expect(err).ToNot(HaveOccurred()) 166 Expect(result).To(Equal(1)) 167 168 exportConn.Close() 169 importConn.Close() 170 }) 171 It("handles concurrent delete", func() { 172 query := "SELECT count(*) FROM snapshot_test" 173 var result int 174 exportConn := testutils.SetupTestDbConn("testdb") 175 importConn := testutils.SetupTestDbConn("testdb") 176 connectionPool.Exec("INSERT INTO snapshot_test SELECT a FROM generate_series(1,5) a") 177 178 exportConn.MustBegin(0) 179 snapshotId, err := backup.GetSynchronizedSnapshot(exportConn) 180 Expect(err).ToNot(HaveOccurred()) 181 // External command deletes row 182 connectionPool.Exec("DELETE FROM snapshot_test where a=1") 183 connectionPool.Get(&result, query) 184 Expect(result).To(Equal(4)) 185 186 // export should see all 5 rows 187 err = exportConn.Get(&result, query) 188 Expect(err).ToNot(HaveOccurred()) 189 Expect(result).To(Equal(5)) 190 191 // import should see 4 rows 192 err = importConn.Get(&result, query) 193 Expect(err).ToNot(HaveOccurred()) 194 Expect(result).To(Equal(4)) 195 196 importConn.MustBegin(0) 197 err = backup.SetSynchronizedSnapshot(importConn, 0, snapshotId) 198 // Should see snapshot with 5 rows 199 Expect(err).ToNot(HaveOccurred()) 200 importConn.Get(&result, query) 201 Expect(result).To(Equal(5)) 202 203 // after commits, deleted row is not visible to either conn 204 err = exportConn.Commit(0) 205 Expect(err).ToNot(HaveOccurred()) 206 err = importConn.Commit(0) 207 Expect(err).ToNot(HaveOccurred()) 208 209 err = exportConn.Get(&result, query) 210 Expect(err).ToNot(HaveOccurred()) 211 Expect(result).To(Equal(4)) 212 213 err = importConn.Get(&result, query) 214 Expect(err).ToNot(HaveOccurred()) 215 Expect(result).To(Equal(4)) 216 217 exportConn.Close() 218 importConn.Close() 219 }) 220 }) 221 })