log_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package raft
  14. import (
  15. "reflect"
  16. "testing"
  17. pb "github.com/coreos/etcd/raft/raftpb"
  18. )
  19. func TestFindConflict(t *testing.T) {
  20. previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
  21. tests := []struct {
  22. ents []pb.Entry
  23. wconflict uint64
  24. }{
  25. // no conflict, empty ent
  26. {[]pb.Entry{}, 0},
  27. {[]pb.Entry{}, 0},
  28. // no conflict
  29. {[]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}, 0},
  30. {[]pb.Entry{{Index: 2, Term: 2}, {Index: 3, Term: 3}}, 0},
  31. {[]pb.Entry{{Index: 3, Term: 3}}, 0},
  32. // no conflict, but has new entries
  33. {[]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
  34. {[]pb.Entry{{Index: 2, Term: 2}, {Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
  35. {[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
  36. {[]pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
  37. // conflicts with existing entries
  38. {[]pb.Entry{{Index: 1, Term: 4}, {Index: 2, Term: 4}}, 1},
  39. {[]pb.Entry{{Index: 2, Term: 1}, {Index: 3, Term: 4}, {Index: 4, Term: 4}}, 2},
  40. {[]pb.Entry{{Index: 3, Term: 1}, {Index: 4, Term: 2}, {Index: 5, Term: 4}, {Index: 6, Term: 4}}, 3},
  41. }
  42. for i, tt := range tests {
  43. raftLog := newLog(NewMemoryStorage())
  44. raftLog.append(previousEnts...)
  45. gconflict := raftLog.findConflict(tt.ents)
  46. if gconflict != tt.wconflict {
  47. t.Errorf("#%d: conflict = %d, want %d", i, gconflict, tt.wconflict)
  48. }
  49. }
  50. }
  51. func TestIsUpToDate(t *testing.T) {
  52. previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
  53. raftLog := newLog(NewMemoryStorage())
  54. raftLog.append(previousEnts...)
  55. tests := []struct {
  56. lastIndex uint64
  57. term uint64
  58. wUpToDate bool
  59. }{
  60. // greater term, ignore lastIndex
  61. {raftLog.lastIndex() - 1, 4, true},
  62. {raftLog.lastIndex(), 4, true},
  63. {raftLog.lastIndex() + 1, 4, true},
  64. // smaller term, ignore lastIndex
  65. {raftLog.lastIndex() - 1, 2, false},
  66. {raftLog.lastIndex(), 2, false},
  67. {raftLog.lastIndex() + 1, 2, false},
  68. // equal term, lager lastIndex wins
  69. {raftLog.lastIndex() - 1, 3, false},
  70. {raftLog.lastIndex(), 3, true},
  71. {raftLog.lastIndex() + 1, 3, true},
  72. }
  73. for i, tt := range tests {
  74. gUpToDate := raftLog.isUpToDate(tt.lastIndex, tt.term)
  75. if gUpToDate != tt.wUpToDate {
  76. t.Errorf("#%d: uptodate = %v, want %v", i, gUpToDate, tt.wUpToDate)
  77. }
  78. }
  79. }
  80. func TestAppend(t *testing.T) {
  81. previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}
  82. tests := []struct {
  83. ents []pb.Entry
  84. windex uint64
  85. wents []pb.Entry
  86. wunstable uint64
  87. }{
  88. {
  89. []pb.Entry{},
  90. 2,
  91. []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}},
  92. 3,
  93. },
  94. {
  95. []pb.Entry{{Index: 3, Term: 2}},
  96. 3,
  97. []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 2}},
  98. 3,
  99. },
  100. // conflicts with index 1
  101. {
  102. []pb.Entry{{Index: 1, Term: 2}},
  103. 1,
  104. []pb.Entry{{Index: 1, Term: 2}},
  105. 1,
  106. },
  107. // conflicts with index 2
  108. {
  109. []pb.Entry{{Index: 2, Term: 3}, {Index: 3, Term: 3}},
  110. 3,
  111. []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 3}, {Index: 3, Term: 3}},
  112. 2,
  113. },
  114. }
  115. for i, tt := range tests {
  116. storage := NewMemoryStorage()
  117. storage.Append(previousEnts)
  118. raftLog := newLog(storage)
  119. index := raftLog.append(tt.ents...)
  120. if index != tt.windex {
  121. t.Errorf("#%d: lastIndex = %d, want %d", i, index, tt.windex)
  122. }
  123. if g := raftLog.entries(1); !reflect.DeepEqual(g, tt.wents) {
  124. t.Errorf("#%d: logEnts = %+v, want %+v", i, g, tt.wents)
  125. }
  126. if g := raftLog.unstable.offset; g != tt.wunstable {
  127. t.Errorf("#%d: unstable = %d, want %d", i, g, tt.wunstable)
  128. }
  129. }
  130. }
  131. // TestLogMaybeAppend ensures:
  132. // If the given (index, term) matches with the existing log:
  133. // 1. If an existing entry conflicts with a new one (same index
  134. // but different terms), delete the existing entry and all that
  135. // follow it
  136. // 2.Append any new entries not already in the log
  137. // If the given (index, term) does not match with the existing log:
  138. // return false
  139. func TestLogMaybeAppend(t *testing.T) {
  140. previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
  141. lastindex := uint64(3)
  142. lastterm := uint64(3)
  143. commit := uint64(1)
  144. tests := []struct {
  145. logTerm uint64
  146. index uint64
  147. committed uint64
  148. ents []pb.Entry
  149. wlasti uint64
  150. wappend bool
  151. wcommit uint64
  152. wpanic bool
  153. }{
  154. // not match: term is different
  155. {
  156. lastterm - 1, lastindex, lastindex, []pb.Entry{{Index: lastindex + 1, Term: 4}},
  157. 0, false, commit, false,
  158. },
  159. // not match: index out of bound
  160. {
  161. lastterm, lastindex + 1, lastindex, []pb.Entry{{Index: lastindex + 2, Term: 4}},
  162. 0, false, commit, false,
  163. },
  164. // match with the last existing entry
  165. {
  166. lastterm, lastindex, lastindex, nil,
  167. lastindex, true, lastindex, false,
  168. },
  169. {
  170. lastterm, lastindex, lastindex + 1, nil,
  171. lastindex, true, lastindex, false, // do not increase commit higher than lastnewi
  172. },
  173. {
  174. lastterm, lastindex, lastindex - 1, nil,
  175. lastindex, true, lastindex - 1, false, // commit up to the commit in the message
  176. },
  177. {
  178. lastterm, lastindex, 0, nil,
  179. lastindex, true, commit, false, // commit do not decrease
  180. },
  181. {
  182. 0, 0, lastindex, nil,
  183. 0, true, commit, false, // commit do not decrease
  184. },
  185. {
  186. lastterm, lastindex, lastindex, []pb.Entry{{Index: lastindex + 1, Term: 4}},
  187. lastindex + 1, true, lastindex, false,
  188. },
  189. {
  190. lastterm, lastindex, lastindex + 1, []pb.Entry{{Index: lastindex + 1, Term: 4}},
  191. lastindex + 1, true, lastindex + 1, false,
  192. },
  193. {
  194. lastterm, lastindex, lastindex + 2, []pb.Entry{{Index: lastindex + 1, Term: 4}},
  195. lastindex + 1, true, lastindex + 1, false, // do not increase commit higher than lastnewi
  196. },
  197. {
  198. lastterm, lastindex, lastindex + 2, []pb.Entry{{Index: lastindex + 1, Term: 4}, {Index: lastindex + 2, Term: 4}},
  199. lastindex + 2, true, lastindex + 2, false,
  200. },
  201. // match with the the entry in the middle
  202. {
  203. lastterm - 1, lastindex - 1, lastindex, []pb.Entry{{Index: lastindex, Term: 4}},
  204. lastindex, true, lastindex, false,
  205. },
  206. {
  207. lastterm - 2, lastindex - 2, lastindex, []pb.Entry{{Index: lastindex - 1, Term: 4}},
  208. lastindex - 1, true, lastindex - 1, false,
  209. },
  210. {
  211. lastterm - 3, lastindex - 3, lastindex, []pb.Entry{{Index: lastindex - 2, Term: 4}},
  212. lastindex - 2, true, lastindex - 2, true, // conflict with existing committed entry
  213. },
  214. {
  215. lastterm - 2, lastindex - 2, lastindex, []pb.Entry{{Index: lastindex - 1, Term: 4}, {Index: lastindex, Term: 4}},
  216. lastindex, true, lastindex, false,
  217. },
  218. }
  219. for i, tt := range tests {
  220. raftLog := newLog(NewMemoryStorage())
  221. raftLog.append(previousEnts...)
  222. raftLog.committed = commit
  223. func() {
  224. defer func() {
  225. if r := recover(); r != nil {
  226. if tt.wpanic != true {
  227. t.Errorf("%d: panic = %v, want %v", i, true, tt.wpanic)
  228. }
  229. }
  230. }()
  231. glasti, gappend := raftLog.maybeAppend(tt.index, tt.logTerm, tt.committed, tt.ents...)
  232. gcommit := raftLog.committed
  233. if glasti != tt.wlasti {
  234. t.Errorf("#%d: lastindex = %d, want %d", i, glasti, tt.wlasti)
  235. }
  236. if gappend != tt.wappend {
  237. t.Errorf("#%d: append = %v, want %v", i, gappend, tt.wappend)
  238. }
  239. if gcommit != tt.wcommit {
  240. t.Errorf("#%d: committed = %d, want %d", i, gcommit, tt.wcommit)
  241. }
  242. if gappend && len(tt.ents) != 0 {
  243. gents := raftLog.slice(raftLog.lastIndex()-uint64(len(tt.ents))+1, raftLog.lastIndex()+1)
  244. if !reflect.DeepEqual(tt.ents, gents) {
  245. t.Errorf("%d: appended entries = %v, want %v", i, gents, tt.ents)
  246. }
  247. }
  248. }()
  249. }
  250. }
  251. // TestCompactionSideEffects ensures that all the log related funcationality works correctly after
  252. // a compaction.
  253. func TestCompactionSideEffects(t *testing.T) {
  254. var i uint64
  255. // Populate the log with 1000 entries; 750 in stable storage and 250 in unstable.
  256. lastIndex := uint64(1000)
  257. unstableIndex := uint64(750)
  258. lastTerm := lastIndex
  259. storage := NewMemoryStorage()
  260. for i = 1; i <= unstableIndex; i++ {
  261. storage.Append([]pb.Entry{{Term: uint64(i), Index: uint64(i)}})
  262. }
  263. raftLog := newLog(storage)
  264. for i = unstableIndex; i < lastIndex; i++ {
  265. raftLog.append(pb.Entry{Term: uint64(i + 1), Index: uint64(i + 1)})
  266. }
  267. ok := raftLog.maybeCommit(lastIndex, lastTerm)
  268. if !ok {
  269. t.Fatalf("maybeCommit returned false")
  270. }
  271. raftLog.appliedTo(raftLog.committed)
  272. offset := uint64(500)
  273. storage.Compact(offset, nil, nil)
  274. if raftLog.lastIndex() != lastIndex {
  275. t.Errorf("lastIndex = %d, want %d", raftLog.lastIndex(), lastIndex)
  276. }
  277. for i := offset; i <= raftLog.lastIndex(); i++ {
  278. if raftLog.term(i) != i {
  279. t.Errorf("term(%d) = %d, want %d", i, raftLog.term(i), i)
  280. }
  281. }
  282. for i := offset; i <= raftLog.lastIndex(); i++ {
  283. if !raftLog.matchTerm(i, i) {
  284. t.Errorf("matchTerm(%d) = false, want true", i)
  285. }
  286. }
  287. unstableEnts := raftLog.unstableEntries()
  288. if g := len(unstableEnts); g != 250 {
  289. t.Errorf("len(unstableEntries) = %d, want = %d", g, 250)
  290. }
  291. if unstableEnts[0].Index != 751 {
  292. t.Errorf("Index = %d, want = %d", unstableEnts[0].Index, 751)
  293. }
  294. prev := raftLog.lastIndex()
  295. raftLog.append(pb.Entry{Index: raftLog.lastIndex() + 1, Term: raftLog.lastIndex() + 1})
  296. if raftLog.lastIndex() != prev+1 {
  297. t.Errorf("lastIndex = %d, want = %d", raftLog.lastIndex(), prev+1)
  298. }
  299. ents := raftLog.entries(raftLog.lastIndex())
  300. if len(ents) != 1 {
  301. t.Errorf("len(entries) = %d, want = %d", len(ents), 1)
  302. }
  303. }
  304. func TestNextEnts(t *testing.T) {
  305. snap := pb.Snapshot{
  306. Metadata: pb.SnapshotMetadata{Term: 1, Index: 3},
  307. }
  308. ents := []pb.Entry{
  309. {Term: 1, Index: 4},
  310. {Term: 1, Index: 5},
  311. {Term: 1, Index: 6},
  312. }
  313. tests := []struct {
  314. applied uint64
  315. wents []pb.Entry
  316. }{
  317. {0, ents[:2]},
  318. {3, ents[:2]},
  319. {4, ents[1:2]},
  320. {5, nil},
  321. }
  322. for i, tt := range tests {
  323. storage := NewMemoryStorage()
  324. storage.ApplySnapshot(snap)
  325. raftLog := newLog(storage)
  326. raftLog.append(ents...)
  327. raftLog.maybeCommit(5, 1)
  328. raftLog.appliedTo(tt.applied)
  329. ents := raftLog.nextEnts()
  330. if !reflect.DeepEqual(ents, tt.wents) {
  331. t.Errorf("#%d: ents = %+v, want %+v", i, ents, tt.wents)
  332. }
  333. }
  334. }
  335. // TestUnstableEnts ensures unstableEntries returns the unstable part of the
  336. // entries correctly.
  337. func TestUnstableEnts(t *testing.T) {
  338. previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}}
  339. tests := []struct {
  340. unstable uint64
  341. wents []pb.Entry
  342. }{
  343. {3, nil},
  344. {1, previousEnts},
  345. }
  346. for i, tt := range tests {
  347. // append stable entries to storage
  348. storage := NewMemoryStorage()
  349. storage.Append(previousEnts[:tt.unstable-1])
  350. // append unstable entries to raftlog
  351. raftLog := newLog(storage)
  352. raftLog.append(previousEnts[tt.unstable-1:]...)
  353. ents := raftLog.unstableEntries()
  354. if l := len(ents); l > 0 {
  355. raftLog.stableTo(ents[l-1].Index, ents[l-i].Term)
  356. }
  357. if !reflect.DeepEqual(ents, tt.wents) {
  358. t.Errorf("#%d: unstableEnts = %+v, want %+v", i, ents, tt.wents)
  359. }
  360. w := previousEnts[len(previousEnts)-1].Index + 1
  361. if g := raftLog.unstable.offset; g != w {
  362. t.Errorf("#%d: unstable = %d, want %d", i, g, w)
  363. }
  364. }
  365. }
  366. func TestCommitTo(t *testing.T) {
  367. previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}, {Term: 3, Index: 3}}
  368. commit := uint64(2)
  369. tests := []struct {
  370. commit uint64
  371. wcommit uint64
  372. wpanic bool
  373. }{
  374. {3, 3, false},
  375. {1, 2, false}, // never decrease
  376. {4, 0, true}, // commit out of range -> panic
  377. }
  378. for i, tt := range tests {
  379. func() {
  380. defer func() {
  381. if r := recover(); r != nil {
  382. if tt.wpanic != true {
  383. t.Errorf("%d: panic = %v, want %v", i, true, tt.wpanic)
  384. }
  385. }
  386. }()
  387. raftLog := newLog(NewMemoryStorage())
  388. raftLog.append(previousEnts...)
  389. raftLog.committed = commit
  390. raftLog.commitTo(tt.commit)
  391. if raftLog.committed != tt.wcommit {
  392. t.Errorf("#%d: committed = %d, want %d", i, raftLog.committed, tt.wcommit)
  393. }
  394. }()
  395. }
  396. }
  397. func TestStableTo(t *testing.T) {
  398. tests := []struct {
  399. stablei uint64
  400. stablet uint64
  401. wunstable uint64
  402. }{
  403. {1, 1, 2},
  404. {2, 2, 3},
  405. {2, 1, 1}, // bad term
  406. {3, 1, 1}, // bad index
  407. }
  408. for i, tt := range tests {
  409. raftLog := newLog(NewMemoryStorage())
  410. raftLog.append([]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}...)
  411. raftLog.stableTo(tt.stablei, tt.stablet)
  412. if raftLog.unstable.offset != tt.wunstable {
  413. t.Errorf("#%d: unstable = %d, want %d", i, raftLog.unstable.offset, tt.wunstable)
  414. }
  415. }
  416. }
  417. func TestStableToWithSnap(t *testing.T) {
  418. snapi, snapt := uint64(5), uint64(2)
  419. tests := []struct {
  420. stablei uint64
  421. stablet uint64
  422. newEnts []pb.Entry
  423. wunstable uint64
  424. }{
  425. {snapi + 1, snapt, nil, snapi + 1},
  426. {snapi, snapt, nil, snapi + 1},
  427. {snapi - 1, snapt, nil, snapi + 1},
  428. {snapi + 1, snapt + 1, nil, snapi + 1},
  429. {snapi, snapt + 1, nil, snapi + 1},
  430. {snapi - 1, snapt + 1, nil, snapi + 1},
  431. {snapi + 1, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 2},
  432. {snapi, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
  433. {snapi - 1, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
  434. {snapi + 1, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
  435. {snapi, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
  436. {snapi - 1, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
  437. }
  438. for i, tt := range tests {
  439. s := NewMemoryStorage()
  440. s.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: snapi, Term: snapt}})
  441. raftLog := newLog(s)
  442. raftLog.append(tt.newEnts...)
  443. raftLog.stableTo(tt.stablei, tt.stablet)
  444. if raftLog.unstable.offset != tt.wunstable {
  445. t.Errorf("#%d: unstable = %d, want %d", i, raftLog.unstable.offset, tt.wunstable)
  446. }
  447. }
  448. }
  449. //TestCompaction ensures that the number of log entries is correct after compactions.
  450. func TestCompaction(t *testing.T) {
  451. tests := []struct {
  452. lastIndex uint64
  453. compact []uint64
  454. wleft []int
  455. wallow bool
  456. }{
  457. // out of upper bound
  458. {1000, []uint64{1001}, []int{-1}, false},
  459. {1000, []uint64{300, 500, 800, 900}, []int{700, 500, 200, 100}, true},
  460. // out of lower bound
  461. {1000, []uint64{300, 299}, []int{700, -1}, false},
  462. }
  463. for i, tt := range tests {
  464. func() {
  465. defer func() {
  466. if r := recover(); r != nil {
  467. if tt.wallow == true {
  468. t.Errorf("%d: allow = %v, want %v: %v", i, false, true, r)
  469. }
  470. }
  471. }()
  472. storage := NewMemoryStorage()
  473. for i := uint64(1); i <= tt.lastIndex; i++ {
  474. storage.Append([]pb.Entry{{Index: i}})
  475. }
  476. raftLog := newLog(storage)
  477. raftLog.maybeCommit(tt.lastIndex, 0)
  478. raftLog.appliedTo(raftLog.committed)
  479. for j := 0; j < len(tt.compact); j++ {
  480. err := storage.Compact(tt.compact[j], nil, nil)
  481. if err != nil {
  482. if tt.wallow {
  483. t.Errorf("#%d.%d allow = %t, want %t", i, j, false, tt.wallow)
  484. }
  485. continue
  486. }
  487. if len(raftLog.allEntries()) != tt.wleft[j] {
  488. t.Errorf("#%d.%d len = %d, want %d", i, j, len(raftLog.allEntries()), tt.wleft[j])
  489. }
  490. }
  491. }()
  492. }
  493. }
  494. func TestLogRestore(t *testing.T) {
  495. index := uint64(1000)
  496. term := uint64(1000)
  497. snap := pb.SnapshotMetadata{Index: index, Term: term}
  498. storage := NewMemoryStorage()
  499. storage.ApplySnapshot(pb.Snapshot{Metadata: snap})
  500. raftLog := newLog(storage)
  501. if len(raftLog.allEntries()) != 0 {
  502. t.Errorf("len = %d, want 0", len(raftLog.allEntries()))
  503. }
  504. if raftLog.firstIndex() != index+1 {
  505. t.Errorf("firstIndex = %d, want %d", raftLog.firstIndex(), index+1)
  506. }
  507. if raftLog.committed != index {
  508. t.Errorf("committed = %d, want %d", raftLog.committed, index)
  509. }
  510. if raftLog.unstable.offset != index+1 {
  511. t.Errorf("unstable = %d, want %d", raftLog.unstable, index+1)
  512. }
  513. if raftLog.term(index) != term {
  514. t.Errorf("term = %d, want %d", raftLog.term(index), term)
  515. }
  516. }
  517. func TestIsOutOfBounds(t *testing.T) {
  518. offset := uint64(100)
  519. num := uint64(100)
  520. storage := NewMemoryStorage()
  521. storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset}})
  522. l := newLog(storage)
  523. for i := uint64(1); i <= num; i++ {
  524. l.append(pb.Entry{Index: i + offset})
  525. }
  526. first := offset + 1
  527. tests := []struct {
  528. lo, hi uint64
  529. wpainc bool
  530. }{
  531. {
  532. first - 2, first + 1,
  533. true,
  534. },
  535. {
  536. first - 1, first + 1,
  537. true,
  538. },
  539. {
  540. first, first,
  541. false,
  542. },
  543. {
  544. first + num/2, first + num/2,
  545. false,
  546. },
  547. {
  548. first + num - 1, first + num - 1,
  549. false,
  550. },
  551. {
  552. first + num, first + num,
  553. false,
  554. },
  555. {
  556. first + num, first + num + 1,
  557. true,
  558. },
  559. {
  560. first + num + 1, first + num + 1,
  561. true,
  562. },
  563. }
  564. for i, tt := range tests {
  565. func() {
  566. defer func() {
  567. if r := recover(); r != nil {
  568. if !tt.wpainc {
  569. t.Errorf("%d: panic = %v, want %v: %v", i, true, false, r)
  570. }
  571. }
  572. }()
  573. l.mustCheckOutOfBounds(tt.lo, tt.hi)
  574. if tt.wpainc {
  575. t.Errorf("%d: panic = %v, want %v", i, false, true)
  576. }
  577. }()
  578. }
  579. }
  580. func TestTerm(t *testing.T) {
  581. var i uint64
  582. offset := uint64(100)
  583. num := uint64(100)
  584. storage := NewMemoryStorage()
  585. storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset, Term: 1}})
  586. l := newLog(storage)
  587. for i = 1; i < num; i++ {
  588. l.append(pb.Entry{Index: offset + i, Term: i})
  589. }
  590. tests := []struct {
  591. index uint64
  592. w uint64
  593. }{
  594. {offset - 1, 0},
  595. {offset, 1},
  596. {offset + num/2, num / 2},
  597. {offset + num - 1, num - 1},
  598. {offset + num, 0},
  599. }
  600. for i, tt := range tests {
  601. term := l.term(tt.index)
  602. if !reflect.DeepEqual(term, tt.w) {
  603. t.Errorf("#%d: at = %d, want %d", i, term, tt.w)
  604. }
  605. }
  606. }
  607. func TestTermWithUnstableSnapshot(t *testing.T) {
  608. storagesnapi := uint64(100)
  609. unstablesnapi := storagesnapi + 5
  610. storage := NewMemoryStorage()
  611. storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: storagesnapi, Term: 1}})
  612. l := newLog(storage)
  613. l.restore(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: unstablesnapi, Term: 1}})
  614. tests := []struct {
  615. index uint64
  616. w uint64
  617. }{
  618. // cannot get term from storage
  619. {storagesnapi, 0},
  620. // cannot get term from the gap between storage ents and unstable snapshot
  621. {storagesnapi + 1, 0},
  622. {unstablesnapi - 1, 0},
  623. // get term from unstable snapshot index
  624. {unstablesnapi, 1},
  625. }
  626. for i, tt := range tests {
  627. term := l.term(tt.index)
  628. if !reflect.DeepEqual(term, tt.w) {
  629. t.Errorf("#%d: at = %d, want %d", i, term, tt.w)
  630. }
  631. }
  632. }
  633. func TestSlice(t *testing.T) {
  634. var i uint64
  635. offset := uint64(100)
  636. num := uint64(100)
  637. storage := NewMemoryStorage()
  638. storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset}})
  639. l := newLog(storage)
  640. for i = 1; i < num; i++ {
  641. l.append(pb.Entry{Index: offset + i, Term: offset + i})
  642. }
  643. tests := []struct {
  644. from uint64
  645. to uint64
  646. w []pb.Entry
  647. wpanic bool
  648. }{
  649. {offset - 1, offset + 1, nil, true},
  650. {offset, offset + 1, nil, true},
  651. {offset + num/2, offset + num/2 + 1, []pb.Entry{{Index: offset + num/2, Term: offset + num/2}}, false},
  652. {offset + num - 1, offset + num, []pb.Entry{{Index: offset + num - 1, Term: offset + num - 1}}, false},
  653. {offset + num, offset + num + 1, nil, true},
  654. }
  655. for i, tt := range tests {
  656. func() {
  657. defer func() {
  658. if r := recover(); r != nil {
  659. if !tt.wpanic {
  660. t.Errorf("%d: panic = %v, want %v: %v", i, true, false, r)
  661. }
  662. }
  663. }()
  664. g := l.slice(tt.from, tt.to)
  665. if !reflect.DeepEqual(g, tt.w) {
  666. t.Errorf("#%d: from %d to %d = %v, want %v", i, tt.from, tt.to, g, tt.w)
  667. }
  668. }()
  669. }
  670. }