go.etcd.io/etcd@v3.3.27+incompatible/snap/snapshotter_test.go (about) 1 // Copyright 2015 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package snap 16 17 import ( 18 "fmt" 19 "hash/crc32" 20 "io/ioutil" 21 "os" 22 "path/filepath" 23 "reflect" 24 "testing" 25 26 "github.com/coreos/etcd/pkg/fileutil" 27 "github.com/coreos/etcd/raft/raftpb" 28 "github.com/coreos/etcd/wal/walpb" 29 ) 30 31 var testSnap = &raftpb.Snapshot{ 32 Data: []byte("some snapshot"), 33 Metadata: raftpb.SnapshotMetadata{ 34 ConfState: raftpb.ConfState{ 35 Nodes: []uint64{1, 2, 3}, 36 }, 37 Index: 1, 38 Term: 1, 39 }, 40 } 41 42 func TestSaveAndLoad(t *testing.T) { 43 dir := filepath.Join(os.TempDir(), "snapshot") 44 err := os.Mkdir(dir, 0700) 45 if err != nil { 46 t.Fatal(err) 47 } 48 defer os.RemoveAll(dir) 49 ss := New(dir) 50 err = ss.save(testSnap) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 g, err := ss.Load() 56 if err != nil { 57 t.Errorf("err = %v, want nil", err) 58 } 59 if !reflect.DeepEqual(g, testSnap) { 60 t.Errorf("snap = %#v, want %#v", g, testSnap) 61 } 62 } 63 64 func TestBadCRC(t *testing.T) { 65 dir := filepath.Join(os.TempDir(), "snapshot") 66 err := os.Mkdir(dir, 0700) 67 if err != nil { 68 t.Fatal(err) 69 } 70 defer os.RemoveAll(dir) 71 ss := New(dir) 72 err = ss.save(testSnap) 73 if err != nil { 74 t.Fatal(err) 75 } 76 defer func() { crcTable = crc32.MakeTable(crc32.Castagnoli) }() 77 // switch to use another crc table 78 // fake a crc mismatch 79 crcTable = crc32.MakeTable(crc32.Koopman) 80 81 _, err = Read(filepath.Join(dir, fmt.Sprintf("%016x-%016x.snap", 1, 1))) 82 if err == nil || err != ErrCRCMismatch { 83 t.Errorf("err = %v, want %v", err, ErrCRCMismatch) 84 } 85 } 86 87 func TestFailback(t *testing.T) { 88 dir := filepath.Join(os.TempDir(), "snapshot") 89 err := os.Mkdir(dir, 0700) 90 if err != nil { 91 t.Fatal(err) 92 } 93 defer os.RemoveAll(dir) 94 95 large := fmt.Sprintf("%016x-%016x-%016x.snap", 0xFFFF, 0xFFFF, 0xFFFF) 96 err = ioutil.WriteFile(filepath.Join(dir, large), []byte("bad data"), 0666) 97 if err != nil { 98 t.Fatal(err) 99 } 100 101 ss := New(dir) 102 err = ss.save(testSnap) 103 if err != nil { 104 t.Fatal(err) 105 } 106 107 g, err := ss.Load() 108 if err != nil { 109 t.Errorf("err = %v, want nil", err) 110 } 111 if !reflect.DeepEqual(g, testSnap) { 112 t.Errorf("snap = %#v, want %#v", g, testSnap) 113 } 114 if f, err := os.Open(filepath.Join(dir, large) + ".broken"); err != nil { 115 t.Fatal("broken snapshot does not exist") 116 } else { 117 f.Close() 118 } 119 } 120 121 func TestSnapNames(t *testing.T) { 122 dir := filepath.Join(os.TempDir(), "snapshot") 123 err := os.Mkdir(dir, 0700) 124 if err != nil { 125 t.Fatal(err) 126 } 127 defer os.RemoveAll(dir) 128 for i := 1; i <= 5; i++ { 129 var f *os.File 130 if f, err = os.Create(filepath.Join(dir, fmt.Sprintf("%d.snap", i))); err != nil { 131 t.Fatal(err) 132 } else { 133 f.Close() 134 } 135 } 136 ss := New(dir) 137 names, err := ss.snapNames() 138 if err != nil { 139 t.Errorf("err = %v, want nil", err) 140 } 141 if len(names) != 5 { 142 t.Errorf("len = %d, want 10", len(names)) 143 } 144 w := []string{"5.snap", "4.snap", "3.snap", "2.snap", "1.snap"} 145 if !reflect.DeepEqual(names, w) { 146 t.Errorf("names = %v, want %v", names, w) 147 } 148 } 149 150 func TestLoadNewestSnap(t *testing.T) { 151 dir := filepath.Join(os.TempDir(), "snapshot") 152 err := os.Mkdir(dir, 0700) 153 if err != nil { 154 t.Fatal(err) 155 } 156 defer os.RemoveAll(dir) 157 ss := New(dir) 158 err = ss.save(testSnap) 159 if err != nil { 160 t.Fatal(err) 161 } 162 163 newSnap := *testSnap 164 newSnap.Metadata.Index = 5 165 err = ss.save(&newSnap) 166 if err != nil { 167 t.Fatal(err) 168 } 169 170 cases := []struct { 171 name string 172 availableWalSnaps []walpb.Snapshot 173 expected *raftpb.Snapshot 174 }{ 175 { 176 name: "load-newest", 177 expected: &newSnap, 178 }, 179 { 180 name: "loadnewestavailable-newest", 181 availableWalSnaps: []walpb.Snapshot{{Index: 0, Term: 0}, {Index: 1, Term: 1}, {Index: 5, Term: 1}}, 182 expected: &newSnap, 183 }, 184 { 185 name: "loadnewestavailable-newest-unsorted", 186 availableWalSnaps: []walpb.Snapshot{{Index: 5, Term: 1}, {Index: 1, Term: 1}, {Index: 0, Term: 0}}, 187 expected: &newSnap, 188 }, 189 { 190 name: "loadnewestavailable-previous", 191 availableWalSnaps: []walpb.Snapshot{{Index: 0, Term: 0}, {Index: 1, Term: 1}}, 192 expected: testSnap, 193 }, 194 } 195 196 for _, tc := range cases { 197 t.Run(tc.name, func(t *testing.T) { 198 var err error 199 var g *raftpb.Snapshot 200 if tc.availableWalSnaps != nil { 201 g, err = ss.LoadNewestAvailable(tc.availableWalSnaps) 202 } else { 203 g, err = ss.Load() 204 } 205 if err != nil { 206 t.Errorf("err = %v, want nil", err) 207 } 208 if !reflect.DeepEqual(g, tc.expected) { 209 t.Errorf("snap = %#v, want %#v", g, tc.expected) 210 } 211 }) 212 } 213 } 214 215 func TestNoSnapshot(t *testing.T) { 216 dir := filepath.Join(os.TempDir(), "snapshot") 217 err := os.Mkdir(dir, 0700) 218 if err != nil { 219 t.Fatal(err) 220 } 221 defer os.RemoveAll(dir) 222 ss := New(dir) 223 _, err = ss.Load() 224 if err != ErrNoSnapshot { 225 t.Errorf("err = %v, want %v", err, ErrNoSnapshot) 226 } 227 } 228 229 func TestEmptySnapshot(t *testing.T) { 230 dir := filepath.Join(os.TempDir(), "snapshot") 231 err := os.Mkdir(dir, 0700) 232 if err != nil { 233 t.Fatal(err) 234 } 235 defer os.RemoveAll(dir) 236 237 err = ioutil.WriteFile(filepath.Join(dir, "1.snap"), []byte(""), 0x700) 238 if err != nil { 239 t.Fatal(err) 240 } 241 242 _, err = Read(filepath.Join(dir, "1.snap")) 243 if err != ErrEmptySnapshot { 244 t.Errorf("err = %v, want %v", err, ErrEmptySnapshot) 245 } 246 } 247 248 // TestAllSnapshotBroken ensures snapshotter returns 249 // ErrNoSnapshot if all the snapshots are broken. 250 func TestAllSnapshotBroken(t *testing.T) { 251 dir := filepath.Join(os.TempDir(), "snapshot") 252 err := os.Mkdir(dir, 0700) 253 if err != nil { 254 t.Fatal(err) 255 } 256 defer os.RemoveAll(dir) 257 258 err = ioutil.WriteFile(filepath.Join(dir, "1.snap"), []byte("bad"), 0x700) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 ss := New(dir) 264 _, err = ss.Load() 265 if err != ErrNoSnapshot { 266 t.Errorf("err = %v, want %v", err, ErrNoSnapshot) 267 } 268 } 269 270 func TestReleaseSnapDBs(t *testing.T) { 271 dir := filepath.Join(os.TempDir(), "snapshot") 272 err := os.Mkdir(dir, 0700) 273 if err != nil { 274 t.Fatal(err) 275 } 276 defer os.RemoveAll(dir) 277 278 snapIndices := []uint64{100, 200, 300, 400} 279 for _, index := range snapIndices { 280 filename := filepath.Join(dir, fmt.Sprintf("%016x.snap.db", index)) 281 if err := ioutil.WriteFile(filename, []byte("snap file\n"), 0644); err != nil { 282 t.Fatal(err) 283 } 284 } 285 286 ss := New(dir) 287 288 if err := ss.ReleaseSnapDBs(raftpb.Snapshot{Metadata: raftpb.SnapshotMetadata{Index: 300}}); err != nil { 289 t.Fatal(err) 290 } 291 292 deleted := []uint64{100, 200} 293 for _, index := range deleted { 294 filename := filepath.Join(dir, fmt.Sprintf("%016x.snap.db", index)) 295 if fileutil.Exist(filename) { 296 t.Errorf("expected %s (index: %d) to be deleted, but it still exists", filename, index) 297 } 298 } 299 300 retained := []uint64{300, 400} 301 for _, index := range retained { 302 filename := filepath.Join(dir, fmt.Sprintf("%016x.snap.db", index)) 303 if !fileutil.Exist(filename) { 304 t.Errorf("expected %s (index: %d) to be retained, but it no longer exists", filename, index) 305 } 306 } 307 }