Test_SingleNodeSnapshot_CheckpointFailures tests the Store responds correctly when checkpoint of the underlying database returns an error. This can happen depending on active readers of the database. The Store should handle active readers fine, aborting the snapshot, and handling it next time. This
(t *testing.T)
| 716 | // readers fine, aborting the snapshot, and handling it next time. This tests |
| 717 | // critical code paths which are very rare, but are perfectly possible in production. |
| 718 | func Test_SingleNodeSnapshot_CheckpointFailures(t *testing.T) { |
| 719 | s, ln := mustNewStore(t) |
| 720 | defer ln.Close() |
| 721 | |
| 722 | if err := s.Open(); err != nil { |
| 723 | t.Fatalf("failed to open single-node store: %s", err.Error()) |
| 724 | } |
| 725 | defer s.Close(true) |
| 726 | s.NoSnapshotOnClose = true |
| 727 | if err := s.Bootstrap(NewServer(s.ID(), s.Addr(), true)); err != nil { |
| 728 | t.Fatalf("failed to bootstrap single-node store: %s", err.Error()) |
| 729 | } |
| 730 | if _, err := s.WaitForLeader(10 * time.Second); err != nil { |
| 731 | t.Fatalf("Error waiting for leader: %s", err) |
| 732 | } |
| 733 | |
| 734 | queries := []string{ |
| 735 | `CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`, |
| 736 | `INSERT INTO foo(name) VALUES("fiona")`, |
| 737 | } |
| 738 | mustExecute(t, s, queries) |
| 739 | |
| 740 | //////////////////////////////////////////////////////////////////////////// |
| 741 | // Start testing with stalled queries. |
| 742 | |
| 743 | startStalledQuery := func(srcDB *db.DB) context.CancelFunc { |
| 744 | ctx, cancelFunc := context.WithCancel(context.Background()) |
| 745 | go func() { |
| 746 | srcDB.QueryWithContext(ctx, mustCreateRequest(`SELECT * FROM foo`), false) |
| 747 | }() |
| 748 | time.Sleep(time.Second) |
| 749 | return cancelFunc |
| 750 | } |
| 751 | |
| 752 | srcDB, err := db.Open(s.dbPath, false, true) |
| 753 | if err != nil { |
| 754 | t.Fatalf("failed to open database: %s", err) |
| 755 | } |
| 756 | defer srcDB.Close() |
| 757 | |
| 758 | cancelFunc := startStalledQuery(srcDB) |
| 759 | |
| 760 | // First snapshot, which will be full, will fail due to the reader. |
| 761 | if err := s.Snapshot(0); err == nil { |
| 762 | t.Fatalf("expected error due to blocking reader when attempting first snapshot") |
| 763 | } |
| 764 | |
| 765 | // Release the reader, full snapshot should work. |
| 766 | cancelFunc() |
| 767 | if err := s.Snapshot(0); err != nil { |
| 768 | t.Fatalf("failed to snapshot after canceling reader: %s", err) |
| 769 | } |
| 770 | |
| 771 | ////////////////////////////////////////////////////////////////////////////////// |
| 772 | // Insert a bunch of records, which will be added to the WAL. Then start |
| 773 | // a reader which should be reading from the last page in the WAL. This will |
| 774 | // mean snapshot will be OK. |
| 775 | clear(queries) |
nothing calls this directly
no test coverage detected