github.com/Finschia/finschia-sdk@v0.48.1/snapshots/manager_test.go (about) 1 package snapshots_test 2 3 import ( 4 "errors" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 10 "github.com/Finschia/finschia-sdk/snapshots" 11 "github.com/Finschia/finschia-sdk/snapshots/types" 12 ) 13 14 func TestManager_List(t *testing.T) { 15 store := setupStore(t) 16 manager := snapshots.NewManager(store, nil) 17 18 mgrList, err := manager.List() 19 require.NoError(t, err) 20 storeList, err := store.List() 21 require.NoError(t, err) 22 23 require.NotEmpty(t, storeList) 24 assert.Equal(t, storeList, mgrList) 25 26 // list should not block or error on busy managers 27 manager = setupBusyManager(t) 28 list, err := manager.List() 29 require.NoError(t, err) 30 assert.Equal(t, []*types.Snapshot{}, list) 31 } 32 33 func TestManager_LoadChunk(t *testing.T) { 34 store := setupStore(t) 35 manager := snapshots.NewManager(store, nil) 36 37 // Existing chunk should return body 38 chunk, err := manager.LoadChunk(2, 1, 1) 39 require.NoError(t, err) 40 assert.Equal(t, []byte{2, 1, 1}, chunk) 41 42 // Missing chunk should return nil 43 chunk, err = manager.LoadChunk(2, 1, 9) 44 require.NoError(t, err) 45 assert.Nil(t, chunk) 46 47 // LoadChunk should not block or error on busy managers 48 manager = setupBusyManager(t) 49 chunk, err = manager.LoadChunk(2, 1, 0) 50 require.NoError(t, err) 51 assert.Nil(t, chunk) 52 } 53 54 func TestManager_Take(t *testing.T) { 55 store := setupStore(t) 56 items := [][]byte{ 57 {1, 2, 3}, 58 {4, 5, 6}, 59 {7, 8, 9}, 60 } 61 snapshotter := &mockSnapshotter{ 62 items: items, 63 } 64 expectChunks := snapshotItems(items) 65 manager := snapshots.NewManager(store, snapshotter) 66 67 // nil manager should return error 68 _, err := (*snapshots.Manager)(nil).Create(1) 69 require.Error(t, err) 70 71 // creating a snapshot at a lower height than the latest should error 72 _, err = manager.Create(3) 73 require.Error(t, err) 74 75 // creating a snapshot at a higher height should be fine, and should return it 76 snapshot, err := manager.Create(5) 77 require.NoError(t, err) 78 assert.Equal(t, &types.Snapshot{ 79 Height: 5, 80 Format: snapshotter.SnapshotFormat(), 81 Chunks: 1, 82 Hash: []uint8{0x14, 0x38, 0x97, 0x96, 0xba, 0xe4, 0x81, 0xaf, 0x6c, 0xac, 0xff, 0xa5, 0xb8, 0x7e, 0x63, 0x4b, 0xac, 0x69, 0x3f, 0x38, 0x90, 0x5c, 0x7d, 0x57, 0xb3, 0xf, 0x69, 0x73, 0xb3, 0xa0, 0xe0, 0xad}, 83 Metadata: types.Metadata{ 84 ChunkHashes: checksums(expectChunks), 85 }, 86 }, snapshot) 87 88 storeSnapshot, chunks, err := store.Load(snapshot.Height, snapshot.Format) 89 require.NoError(t, err) 90 assert.Equal(t, snapshot, storeSnapshot) 91 assert.Equal(t, expectChunks, readChunks(chunks)) 92 93 // creating a snapshot while a different snapshot is being created should error 94 manager = setupBusyManager(t) 95 _, err = manager.Create(9) 96 require.Error(t, err) 97 } 98 99 func TestManager_Prune(t *testing.T) { 100 store := setupStore(t) 101 manager := snapshots.NewManager(store, nil) 102 103 pruned, err := manager.Prune(2) 104 require.NoError(t, err) 105 assert.EqualValues(t, 1, pruned) 106 107 list, err := manager.List() 108 require.NoError(t, err) 109 assert.Len(t, list, 3) 110 111 // Prune should error while a snapshot is being taken 112 manager = setupBusyManager(t) 113 _, err = manager.Prune(2) 114 require.Error(t, err) 115 } 116 117 func TestManager_Restore(t *testing.T) { 118 store := setupStore(t) 119 target := &mockSnapshotter{} 120 manager := snapshots.NewManager(store, target) 121 122 expectItems := [][]byte{ 123 {1, 2, 3}, 124 {4, 5, 6}, 125 {7, 8, 9}, 126 } 127 128 chunks := snapshotItems(expectItems) 129 130 // Restore errors on invalid format 131 err := manager.Restore(types.Snapshot{ 132 Height: 3, 133 Format: 0, 134 Hash: []byte{1, 2, 3}, 135 Chunks: uint32(len(chunks)), 136 Metadata: types.Metadata{ChunkHashes: checksums(chunks)}, 137 }) 138 require.Error(t, err) 139 require.ErrorIs(t, err, types.ErrUnknownFormat) 140 141 // Restore errors on no chunks 142 err = manager.Restore(types.Snapshot{Height: 3, Format: 1, Hash: []byte{1, 2, 3}}) 143 require.Error(t, err) 144 145 // Restore errors on chunk and chunkhashes mismatch 146 err = manager.Restore(types.Snapshot{ 147 Height: 3, 148 Format: 1, 149 Hash: []byte{1, 2, 3}, 150 Chunks: 4, 151 Metadata: types.Metadata{ChunkHashes: checksums(chunks)}, 152 }) 153 require.Error(t, err) 154 155 // Starting a restore works 156 err = manager.Restore(types.Snapshot{ 157 Height: 3, 158 Format: 1, 159 Hash: []byte{1, 2, 3}, 160 Chunks: 1, 161 Metadata: types.Metadata{ChunkHashes: checksums(chunks)}, 162 }) 163 require.NoError(t, err) 164 165 // While the restore is in progress, any other operations fail 166 _, err = manager.Create(4) 167 require.Error(t, err) 168 169 _, err = manager.Prune(1) 170 require.Error(t, err) 171 172 // Feeding an invalid chunk should error due to invalid checksum, but not abort restoration. 173 _, err = manager.RestoreChunk([]byte{9, 9, 9}) 174 require.Error(t, err) 175 require.True(t, errors.Is(err, types.ErrChunkHashMismatch)) 176 177 // Feeding the chunks should work 178 for i, chunk := range chunks { 179 done, err := manager.RestoreChunk(chunk) 180 require.NoError(t, err) 181 if i == len(chunks)-1 { 182 assert.True(t, done) 183 } else { 184 assert.False(t, done) 185 } 186 } 187 188 assert.Equal(t, expectItems, target.items) 189 190 // Starting a new restore should fail now, because the target already has contents. 191 err = manager.Restore(types.Snapshot{ 192 Height: 3, 193 Format: 1, 194 Hash: []byte{1, 2, 3}, 195 Chunks: 3, 196 Metadata: types.Metadata{ChunkHashes: checksums(chunks)}, 197 }) 198 require.Error(t, err) 199 200 // But if we clear out the target we should be able to start a new restore. This time we'll 201 // fail it with a checksum error. That error should stop the operation, so that we can do 202 // a prune operation right after. 203 target.items = nil 204 err = manager.Restore(types.Snapshot{ 205 Height: 3, 206 Format: 1, 207 Hash: []byte{1, 2, 3}, 208 Chunks: 1, 209 Metadata: types.Metadata{ChunkHashes: checksums(chunks)}, 210 }) 211 require.NoError(t, err) 212 }