log_test.go 20 KB

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