log_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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{{Term: 1}, {Term: 2}, {Term: 3}}
  21. tests := []struct {
  22. from uint64
  23. ents []pb.Entry
  24. wconflict uint64
  25. }{
  26. // no conflict, empty ent
  27. {1, []pb.Entry{}, 0},
  28. {3, []pb.Entry{}, 0},
  29. // no conflict
  30. {1, []pb.Entry{{Term: 1}, {Term: 2}, {Term: 3}}, 0},
  31. {2, []pb.Entry{{Term: 2}, {Term: 3}}, 0},
  32. {3, []pb.Entry{{Term: 3}}, 0},
  33. // no conflict, but has new entries
  34. {1, []pb.Entry{{Term: 1}, {Term: 2}, {Term: 3}, {Term: 4}, {Term: 4}}, 4},
  35. {2, []pb.Entry{{Term: 2}, {Term: 3}, {Term: 4}, {Term: 4}}, 4},
  36. {3, []pb.Entry{{Term: 3}, {Term: 4}, {Term: 4}}, 4},
  37. {4, []pb.Entry{{Term: 4}, {Term: 4}}, 4},
  38. // conflicts with existing entries
  39. {1, []pb.Entry{{Term: 4}, {Term: 4}}, 1},
  40. {2, []pb.Entry{{Term: 1}, {Term: 4}, {Term: 4}}, 2},
  41. {3, []pb.Entry{{Term: 1}, {Term: 2}, {Term: 4}, {Term: 4}}, 3},
  42. }
  43. for i, tt := range tests {
  44. raftLog := newLog()
  45. raftLog.append(raftLog.lastIndex(), previousEnts...)
  46. gconflict := raftLog.findConflict(tt.from, 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{{Term: 1}, {Term: 2}, {Term: 3}}
  54. raftLog := newLog()
  55. raftLog.append(raftLog.lastIndex(), 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. // TestAppend ensures:
  82. // 1. If an existing entry conflicts with a new one (same index
  83. // but different terms), delete the existing entry and all that
  84. // follow it
  85. // 2.Append any new entries not already in the log
  86. func TestAppend(t *testing.T) {
  87. previousEnts := []pb.Entry{{Term: 1}, {Term: 2}}
  88. previousUnstable := uint64(3)
  89. tests := []struct {
  90. after uint64
  91. ents []pb.Entry
  92. windex uint64
  93. wents []pb.Entry
  94. wunstable uint64
  95. }{
  96. {
  97. 2,
  98. []pb.Entry{},
  99. 2,
  100. []pb.Entry{{Term: 1}, {Term: 2}},
  101. 3,
  102. },
  103. {
  104. 2,
  105. []pb.Entry{{Term: 2}},
  106. 3,
  107. []pb.Entry{{Term: 1}, {Term: 2}, {Term: 2}},
  108. 3,
  109. },
  110. // conflicts with index 1
  111. {
  112. 0,
  113. []pb.Entry{{Term: 2}},
  114. 1,
  115. []pb.Entry{{Term: 2}},
  116. 1,
  117. },
  118. // conflicts with index 2
  119. {
  120. 1,
  121. []pb.Entry{{Term: 3}, {Term: 3}},
  122. 3,
  123. []pb.Entry{{Term: 1}, {Term: 3}, {Term: 3}},
  124. 2,
  125. },
  126. }
  127. for i, tt := range tests {
  128. raftLog := newLog()
  129. raftLog.append(raftLog.lastIndex(), previousEnts...)
  130. raftLog.unstable = previousUnstable
  131. index := raftLog.append(tt.after, tt.ents...)
  132. if index != tt.windex {
  133. t.Errorf("#%d: lastIndex = %d, want %d", i, index, tt.windex)
  134. }
  135. if g := raftLog.entries(1); !reflect.DeepEqual(g, tt.wents) {
  136. t.Errorf("#%d: logEnts = %+v, want %+v", i, g, tt.wents)
  137. }
  138. if g := raftLog.unstable; g != tt.wunstable {
  139. t.Errorf("#%d: unstable = %d, want %d", i, g, tt.wunstable)
  140. }
  141. }
  142. }
  143. // TestCompactionSideEffects ensures that all the log related funcationality works correctly after
  144. // a compaction.
  145. func TestCompactionSideEffects(t *testing.T) {
  146. var i uint64
  147. lastIndex := uint64(1000)
  148. lastTerm := lastIndex
  149. raftLog := newLog()
  150. for i = 0; i < lastIndex; i++ {
  151. raftLog.append(uint64(i), pb.Entry{Term: uint64(i + 1), Index: uint64(i + 1)})
  152. }
  153. raftLog.maybeCommit(lastIndex, lastTerm)
  154. raftLog.resetNextEnts()
  155. raftLog.compact(500)
  156. if raftLog.lastIndex() != lastIndex {
  157. t.Errorf("lastIndex = %d, want %d", raftLog.lastIndex(), lastIndex)
  158. }
  159. for i := raftLog.offset; i <= raftLog.lastIndex(); i++ {
  160. if raftLog.term(i) != i {
  161. t.Errorf("term(%d) = %d, want %d", i, raftLog.term(i), i)
  162. }
  163. }
  164. for i := raftLog.offset; i <= raftLog.lastIndex(); i++ {
  165. if !raftLog.matchTerm(i, i) {
  166. t.Errorf("matchTerm(%d) = false, want true", i)
  167. }
  168. }
  169. unstableEnts := raftLog.unstableEnts()
  170. if g := len(unstableEnts); g != 500 {
  171. t.Errorf("len(unstableEntries) = %d, want = %d", g, 500)
  172. }
  173. if unstableEnts[0].Index != 501 {
  174. t.Errorf("Index = %d, want = %d", unstableEnts[0].Index, 501)
  175. }
  176. prev := raftLog.lastIndex()
  177. raftLog.append(raftLog.lastIndex(), pb.Entry{Term: raftLog.lastIndex() + 1})
  178. if raftLog.lastIndex() != prev+1 {
  179. t.Errorf("lastIndex = %d, want = %d", raftLog.lastIndex(), prev+1)
  180. }
  181. ents := raftLog.entries(raftLog.lastIndex())
  182. if len(ents) != 1 {
  183. t.Errorf("len(entries) = %d, want = %d", len(ents), 1)
  184. }
  185. }
  186. func TestUnstableEnts(t *testing.T) {
  187. previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}}
  188. tests := []struct {
  189. unstable uint64
  190. wents []pb.Entry
  191. wunstable uint64
  192. }{
  193. {3, nil, 3},
  194. {1, previousEnts, 3},
  195. }
  196. for i, tt := range tests {
  197. raftLog := newLog()
  198. raftLog.append(0, previousEnts...)
  199. raftLog.unstable = tt.unstable
  200. ents := raftLog.unstableEnts()
  201. raftLog.resetUnstable()
  202. if !reflect.DeepEqual(ents, tt.wents) {
  203. t.Errorf("#%d: unstableEnts = %+v, want %+v", i, ents, tt.wents)
  204. }
  205. if g := raftLog.unstable; g != tt.wunstable {
  206. t.Errorf("#%d: unstable = %d, want %d", i, g, tt.wunstable)
  207. }
  208. }
  209. }
  210. //TestCompaction ensures that the number of log entreis is correct after compactions.
  211. func TestCompaction(t *testing.T) {
  212. tests := []struct {
  213. applied uint64
  214. lastIndex uint64
  215. compact []uint64
  216. wleft []int
  217. wallow bool
  218. }{
  219. // out of upper bound
  220. {1000, 1000, []uint64{1001}, []int{-1}, false},
  221. {1000, 1000, []uint64{300, 500, 800, 900}, []int{701, 501, 201, 101}, true},
  222. // out of lower bound
  223. {1000, 1000, []uint64{300, 299}, []int{701, -1}, false},
  224. {0, 1000, []uint64{1}, []int{-1}, false},
  225. }
  226. for i, tt := range tests {
  227. func() {
  228. defer func() {
  229. if r := recover(); r != nil {
  230. if tt.wallow == true {
  231. t.Errorf("%d: allow = %v, want %v", i, false, true)
  232. }
  233. }
  234. }()
  235. raftLog := newLog()
  236. for i := uint64(0); i < tt.lastIndex; i++ {
  237. raftLog.append(uint64(i), pb.Entry{})
  238. }
  239. raftLog.maybeCommit(tt.applied, 0)
  240. raftLog.resetNextEnts()
  241. for j := 0; j < len(tt.compact); j++ {
  242. raftLog.compact(tt.compact[j])
  243. if len(raftLog.ents) != tt.wleft[j] {
  244. t.Errorf("#%d.%d len = %d, want %d", i, j, len(raftLog.ents), tt.wleft[j])
  245. }
  246. }
  247. }()
  248. }
  249. }
  250. func TestLogRestore(t *testing.T) {
  251. var i uint64
  252. raftLog := newLog()
  253. for i = 0; i < 100; i++ {
  254. raftLog.append(i, pb.Entry{Term: i + 1})
  255. }
  256. index := uint64(1000)
  257. term := uint64(1000)
  258. raftLog.restore(pb.Snapshot{Index: index, Term: term})
  259. // only has the guard entry
  260. if len(raftLog.ents) != 1 {
  261. t.Errorf("len = %d, want 0", len(raftLog.ents))
  262. }
  263. if raftLog.offset != index {
  264. t.Errorf("offset = %d, want %d", raftLog.offset, index)
  265. }
  266. if raftLog.applied != index {
  267. t.Errorf("applied = %d, want %d", raftLog.applied, index)
  268. }
  269. if raftLog.committed != index {
  270. t.Errorf("comitted = %d, want %d", raftLog.committed, index)
  271. }
  272. if raftLog.unstable != index+1 {
  273. t.Errorf("unstable = %d, want %d", raftLog.unstable, index+1)
  274. }
  275. if raftLog.term(index) != term {
  276. t.Errorf("term = %d, want %d", raftLog.term(index), term)
  277. }
  278. }
  279. func TestIsOutOfBounds(t *testing.T) {
  280. offset := uint64(100)
  281. num := uint64(100)
  282. l := &raftLog{offset: offset, ents: make([]pb.Entry, num)}
  283. tests := []struct {
  284. index uint64
  285. w bool
  286. }{
  287. {offset - 1, true},
  288. {offset, false},
  289. {offset + num/2, false},
  290. {offset + num - 1, false},
  291. {offset + num, true},
  292. }
  293. for i, tt := range tests {
  294. g := l.isOutOfBounds(tt.index)
  295. if g != tt.w {
  296. t.Errorf("#%d: isOutOfBounds = %v, want %v", i, g, tt.w)
  297. }
  298. }
  299. }
  300. func TestAt(t *testing.T) {
  301. var i uint64
  302. offset := uint64(100)
  303. num := uint64(100)
  304. l := &raftLog{offset: offset}
  305. for i = 0; i < num; i++ {
  306. l.ents = append(l.ents, pb.Entry{Term: i})
  307. }
  308. tests := []struct {
  309. index uint64
  310. w *pb.Entry
  311. }{
  312. {offset - 1, nil},
  313. {offset, &pb.Entry{Term: 0}},
  314. {offset + num/2, &pb.Entry{Term: num / 2}},
  315. {offset + num - 1, &pb.Entry{Term: num - 1}},
  316. {offset + num, nil},
  317. }
  318. for i, tt := range tests {
  319. g := l.at(tt.index)
  320. if !reflect.DeepEqual(g, tt.w) {
  321. t.Errorf("#%d: at = %v, want %v", i, g, tt.w)
  322. }
  323. }
  324. }
  325. func TestSlice(t *testing.T) {
  326. var i uint64
  327. offset := uint64(100)
  328. num := uint64(100)
  329. l := &raftLog{offset: offset}
  330. for i = 0; i < num; i++ {
  331. l.ents = append(l.ents, pb.Entry{Term: i})
  332. }
  333. tests := []struct {
  334. from uint64
  335. to uint64
  336. w []pb.Entry
  337. }{
  338. {offset - 1, offset + 1, nil},
  339. {offset, offset + 1, []pb.Entry{{Term: 0}}},
  340. {offset + num/2, offset + num/2 + 1, []pb.Entry{{Term: num / 2}}},
  341. {offset + num - 1, offset + num, []pb.Entry{{Term: num - 1}}},
  342. {offset + num, offset + num + 1, nil},
  343. {offset + num/2, offset + num/2, nil},
  344. {offset + num/2, offset + num/2 - 1, nil},
  345. }
  346. for i, tt := range tests {
  347. g := l.slice(tt.from, tt.to)
  348. if !reflect.DeepEqual(g, tt.w) {
  349. t.Errorf("#%d: from %d to %d = %v, want %v", i, tt.from, tt.to, g, tt.w)
  350. }
  351. }
  352. }