log_unstable_test.go 7.9 KB

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