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  })