go.etcd.io/etcd@v3.3.27+incompatible/raft/log_unstable_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 raft 16 17 import ( 18 "reflect" 19 "testing" 20 21 pb "github.com/coreos/etcd/raft/raftpb" 22 ) 23 24 func TestUnstableMaybeFirstIndex(t *testing.T) { 25 tests := []struct { 26 entries []pb.Entry 27 offset uint64 28 snap *pb.Snapshot 29 30 wok bool 31 windex uint64 32 }{ 33 // no snapshot 34 { 35 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 36 false, 0, 37 }, 38 { 39 []pb.Entry{}, 0, nil, 40 false, 0, 41 }, 42 // has snapshot 43 { 44 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 45 true, 5, 46 }, 47 { 48 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 49 true, 5, 50 }, 51 } 52 53 for i, tt := range tests { 54 u := unstable{ 55 entries: tt.entries, 56 offset: tt.offset, 57 snapshot: tt.snap, 58 logger: raftLogger, 59 } 60 index, ok := u.maybeFirstIndex() 61 if ok != tt.wok { 62 t.Errorf("#%d: ok = %t, want %t", i, ok, tt.wok) 63 } 64 if index != tt.windex { 65 t.Errorf("#%d: index = %d, want %d", i, index, tt.windex) 66 } 67 } 68 } 69 70 func TestMaybeLastIndex(t *testing.T) { 71 tests := []struct { 72 entries []pb.Entry 73 offset uint64 74 snap *pb.Snapshot 75 76 wok bool 77 windex uint64 78 }{ 79 // last in entries 80 { 81 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 82 true, 5, 83 }, 84 { 85 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 86 true, 5, 87 }, 88 // last in snapshot 89 { 90 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 91 true, 4, 92 }, 93 // empty unstable 94 { 95 []pb.Entry{}, 0, nil, 96 false, 0, 97 }, 98 } 99 100 for i, tt := range tests { 101 u := unstable{ 102 entries: tt.entries, 103 offset: tt.offset, 104 snapshot: tt.snap, 105 logger: raftLogger, 106 } 107 index, ok := u.maybeLastIndex() 108 if ok != tt.wok { 109 t.Errorf("#%d: ok = %t, want %t", i, ok, tt.wok) 110 } 111 if index != tt.windex { 112 t.Errorf("#%d: index = %d, want %d", i, index, tt.windex) 113 } 114 } 115 } 116 117 func TestUnstableMaybeTerm(t *testing.T) { 118 tests := []struct { 119 entries []pb.Entry 120 offset uint64 121 snap *pb.Snapshot 122 index uint64 123 124 wok bool 125 wterm uint64 126 }{ 127 // term from entries 128 { 129 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 130 5, 131 true, 1, 132 }, 133 { 134 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 135 6, 136 false, 0, 137 }, 138 { 139 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 140 4, 141 false, 0, 142 }, 143 { 144 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 145 5, 146 true, 1, 147 }, 148 { 149 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 150 6, 151 false, 0, 152 }, 153 // term from snapshot 154 { 155 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 156 4, 157 true, 1, 158 }, 159 { 160 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 161 3, 162 false, 0, 163 }, 164 { 165 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 166 5, 167 false, 0, 168 }, 169 { 170 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 171 4, 172 true, 1, 173 }, 174 { 175 []pb.Entry{}, 0, nil, 176 5, 177 false, 0, 178 }, 179 } 180 181 for i, tt := range tests { 182 u := unstable{ 183 entries: tt.entries, 184 offset: tt.offset, 185 snapshot: tt.snap, 186 logger: raftLogger, 187 } 188 term, ok := u.maybeTerm(tt.index) 189 if ok != tt.wok { 190 t.Errorf("#%d: ok = %t, want %t", i, ok, tt.wok) 191 } 192 if term != tt.wterm { 193 t.Errorf("#%d: term = %d, want %d", i, term, tt.wterm) 194 } 195 } 196 } 197 198 func TestUnstableRestore(t *testing.T) { 199 u := unstable{ 200 entries: []pb.Entry{{Index: 5, Term: 1}}, 201 offset: 5, 202 snapshot: &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 203 logger: raftLogger, 204 } 205 s := pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 6, Term: 2}} 206 u.restore(s) 207 208 if u.offset != s.Metadata.Index+1 { 209 t.Errorf("offset = %d, want %d", u.offset, s.Metadata.Index+1) 210 } 211 if len(u.entries) != 0 { 212 t.Errorf("len = %d, want 0", len(u.entries)) 213 } 214 if !reflect.DeepEqual(u.snapshot, &s) { 215 t.Errorf("snap = %v, want %v", u.snapshot, &s) 216 } 217 } 218 219 func TestUnstableStableTo(t *testing.T) { 220 tests := []struct { 221 entries []pb.Entry 222 offset uint64 223 snap *pb.Snapshot 224 index, term uint64 225 226 woffset uint64 227 wlen int 228 }{ 229 { 230 []pb.Entry{}, 0, nil, 231 5, 1, 232 0, 0, 233 }, 234 { 235 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 236 5, 1, // stable to the first entry 237 6, 0, 238 }, 239 { 240 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, nil, 241 5, 1, // stable to the first entry 242 6, 1, 243 }, 244 { 245 []pb.Entry{{Index: 6, Term: 2}}, 6, nil, 246 6, 1, // stable to the first entry and term mismatch 247 6, 1, 248 }, 249 { 250 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 251 4, 1, // stable to old entry 252 5, 1, 253 }, 254 { 255 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 256 4, 2, // stable to old entry 257 5, 1, 258 }, 259 // with snapshot 260 { 261 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 262 5, 1, // stable to the first entry 263 6, 0, 264 }, 265 { 266 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 267 5, 1, // stable to the first entry 268 6, 1, 269 }, 270 { 271 []pb.Entry{{Index: 6, Term: 2}}, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 5, Term: 1}}, 272 6, 1, // stable to the first entry and term mismatch 273 6, 1, 274 }, 275 { 276 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 277 4, 1, // stable to snapshot 278 5, 1, 279 }, 280 { 281 []pb.Entry{{Index: 5, Term: 2}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 2}}, 282 4, 1, // stable to old entry 283 5, 1, 284 }, 285 } 286 287 for i, tt := range tests { 288 u := unstable{ 289 entries: tt.entries, 290 offset: tt.offset, 291 snapshot: tt.snap, 292 logger: raftLogger, 293 } 294 u.stableTo(tt.index, tt.term) 295 if u.offset != tt.woffset { 296 t.Errorf("#%d: offset = %d, want %d", i, u.offset, tt.woffset) 297 } 298 if len(u.entries) != tt.wlen { 299 t.Errorf("#%d: len = %d, want %d", i, len(u.entries), tt.wlen) 300 } 301 } 302 } 303 304 func TestUnstableTruncateAndAppend(t *testing.T) { 305 tests := []struct { 306 entries []pb.Entry 307 offset uint64 308 snap *pb.Snapshot 309 toappend []pb.Entry 310 311 woffset uint64 312 wentries []pb.Entry 313 }{ 314 // append to the end 315 { 316 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 317 []pb.Entry{{Index: 6, Term: 1}, {Index: 7, Term: 1}}, 318 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 319 }, 320 // replace the unstable entries 321 { 322 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 323 []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}}, 324 5, []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}}, 325 }, 326 { 327 []pb.Entry{{Index: 5, Term: 1}}, 5, nil, 328 []pb.Entry{{Index: 4, Term: 2}, {Index: 5, Term: 2}, {Index: 6, Term: 2}}, 329 4, []pb.Entry{{Index: 4, Term: 2}, {Index: 5, Term: 2}, {Index: 6, Term: 2}}, 330 }, 331 // truncate the existing entries and append 332 { 333 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, nil, 334 []pb.Entry{{Index: 6, Term: 2}}, 335 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 2}}, 336 }, 337 { 338 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, nil, 339 []pb.Entry{{Index: 7, Term: 2}, {Index: 8, Term: 2}}, 340 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 2}, {Index: 8, Term: 2}}, 341 }, 342 } 343 344 for i, tt := range tests { 345 u := unstable{ 346 entries: tt.entries, 347 offset: tt.offset, 348 snapshot: tt.snap, 349 logger: raftLogger, 350 } 351 u.truncateAndAppend(tt.toappend) 352 if u.offset != tt.woffset { 353 t.Errorf("#%d: offset = %d, want %d", i, u.offset, tt.woffset) 354 } 355 if !reflect.DeepEqual(u.entries, tt.wentries) { 356 t.Errorf("#%d: entries = %v, want %v", i, u.entries, tt.wentries) 357 } 358 } 359 }