log_test.go 9.0 KB

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