token_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. // Copyright (c) 2015 The gocql Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gocql
  5. import (
  6. "bytes"
  7. "math/big"
  8. "sort"
  9. "strconv"
  10. "testing"
  11. )
  12. // Test the implementation of murmur3
  13. func TestMurmur3H1(t *testing.T) {
  14. // these examples are based on adding a index number to a sample string in
  15. // a loop. The expected values were generated by the java datastax murmur3
  16. // implementation. The number of examples here of increasing lengths ensure
  17. // test coverage of all tail-length branches in the murmur3 algorithm
  18. seriesExpected := [...]uint64{
  19. 0x0000000000000000, // ""
  20. 0x2ac9debed546a380, // "0"
  21. 0x649e4eaa7fc1708e, // "01"
  22. 0xce68f60d7c353bdb, // "012"
  23. 0x0f95757ce7f38254, // "0123"
  24. 0x0f04e459497f3fc1, // "01234"
  25. 0x88c0a92586be0a27, // "012345"
  26. 0x13eb9fb82606f7a6, // "0123456"
  27. 0x8236039b7387354d, // "01234567"
  28. 0x4c1e87519fe738ba, // "012345678"
  29. 0x3f9652ac3effeb24, // "0123456789"
  30. 0x3f33760ded9006c6, // "01234567890"
  31. 0xaed70a6631854cb1, // "012345678901"
  32. 0x8a299a8f8e0e2da7, // "0123456789012"
  33. 0x624b675c779249a6, // "01234567890123"
  34. 0xa4b203bb1d90b9a3, // "012345678901234"
  35. 0xa3293ad698ecb99a, // "0123456789012345"
  36. 0xbc740023dbd50048, // "01234567890123456"
  37. 0x3fe5ab9837d25cdd, // "012345678901234567"
  38. 0x2d0338c1ca87d132, // "0123456789012345678"
  39. }
  40. sample := ""
  41. for i, expected := range seriesExpected {
  42. assertMurmur3H1(t, []byte(sample), expected)
  43. sample = sample + strconv.Itoa(i%10)
  44. }
  45. // Here are some test examples from other driver implementations
  46. assertMurmur3H1(t, []byte("hello"), 0xcbd8a7b341bd9b02)
  47. assertMurmur3H1(t, []byte("hello, world"), 0x342fac623a5ebc8e)
  48. assertMurmur3H1(t, []byte("19 Jan 2038 at 3:14:07 AM"), 0xb89e5988b737affc)
  49. assertMurmur3H1(t, []byte("The quick brown fox jumps over the lazy dog."), 0xcd99481f9ee902c9)
  50. }
  51. // helper function for testing the murmur3 implementation
  52. func assertMurmur3H1(t *testing.T, data []byte, expected uint64) {
  53. actual := murmur3H1(data)
  54. if actual != expected {
  55. t.Errorf("Expected h1 = %x for data = %x, but was %x", expected, data, actual)
  56. }
  57. }
  58. // Benchmark of the performance of the murmur3 implementation
  59. func BenchmarkMurmur3H1(b *testing.B) {
  60. var h1 uint64
  61. var data [1024]byte
  62. for i := 0; i < 1024; i++ {
  63. data[i] = byte(i)
  64. }
  65. for i := 0; i < b.N; i++ {
  66. b.ResetTimer()
  67. h1 = murmur3H1(data[:])
  68. _ = murmur3Token(int64(h1))
  69. }
  70. }
  71. // Tests of the murmur3Patitioner
  72. func TestMurmur3Partitioner(t *testing.T) {
  73. token := murmur3Partitioner{}.ParseString("-1053604476080545076")
  74. if "-1053604476080545076" != token.String() {
  75. t.Errorf("Expected '-1053604476080545076' but was '%s'", token)
  76. }
  77. // at least verify that the partitioner
  78. // doesn't return nil
  79. pk, _ := marshalInt(nil, 1)
  80. token = murmur3Partitioner{}.Hash(pk)
  81. if token == nil {
  82. t.Fatal("token was nil")
  83. }
  84. }
  85. // Tests of the murmur3Token
  86. func TestMurmur3Token(t *testing.T) {
  87. if murmur3Token(42).Less(murmur3Token(42)) {
  88. t.Errorf("Expected Less to return false, but was true")
  89. }
  90. if !murmur3Token(-42).Less(murmur3Token(42)) {
  91. t.Errorf("Expected Less to return true, but was false")
  92. }
  93. if murmur3Token(42).Less(murmur3Token(-42)) {
  94. t.Errorf("Expected Less to return false, but was true")
  95. }
  96. }
  97. // Tests of the orderedPartitioner
  98. func TestOrderedPartitioner(t *testing.T) {
  99. // at least verify that the partitioner
  100. // doesn't return nil
  101. p := orderedPartitioner{}
  102. pk, _ := marshalInt(nil, 1)
  103. token := p.Hash(pk)
  104. if token == nil {
  105. t.Fatal("token was nil")
  106. }
  107. str := token.String()
  108. parsedToken := p.ParseString(str)
  109. if !bytes.Equal([]byte(token.(orderedToken)), []byte(parsedToken.(orderedToken))) {
  110. t.Errorf("Failed to convert to and from a string %s expected %x but was %x",
  111. str,
  112. []byte(token.(orderedToken)),
  113. []byte(parsedToken.(orderedToken)),
  114. )
  115. }
  116. }
  117. // Tests of the orderedToken
  118. func TestOrderedToken(t *testing.T) {
  119. if orderedToken([]byte{0, 0, 4, 2}).Less(orderedToken([]byte{0, 0, 4, 2})) {
  120. t.Errorf("Expected Less to return false, but was true")
  121. }
  122. if !orderedToken([]byte{0, 0, 3}).Less(orderedToken([]byte{0, 0, 4, 2})) {
  123. t.Errorf("Expected Less to return true, but was false")
  124. }
  125. if orderedToken([]byte{0, 0, 4, 2}).Less(orderedToken([]byte{0, 0, 3})) {
  126. t.Errorf("Expected Less to return false, but was true")
  127. }
  128. }
  129. // Tests of the randomPartitioner
  130. func TestRandomPartitioner(t *testing.T) {
  131. // at least verify that the partitioner
  132. // doesn't return nil
  133. p := randomPartitioner{}
  134. pk, _ := marshalInt(nil, 1)
  135. token := p.Hash(pk)
  136. if token == nil {
  137. t.Fatal("token was nil")
  138. }
  139. str := token.String()
  140. parsedToken := p.ParseString(str)
  141. if (*big.Int)(token.(*randomToken)).Cmp((*big.Int)(parsedToken.(*randomToken))) != 0 {
  142. t.Errorf("Failed to convert to and from a string %s expected %v but was %v",
  143. str,
  144. token,
  145. parsedToken,
  146. )
  147. }
  148. }
  149. // Tests of the randomToken
  150. func TestRandomToken(t *testing.T) {
  151. if ((*randomToken)(big.NewInt(42))).Less((*randomToken)(big.NewInt(42))) {
  152. t.Errorf("Expected Less to return false, but was true")
  153. }
  154. if !((*randomToken)(big.NewInt(41))).Less((*randomToken)(big.NewInt(42))) {
  155. t.Errorf("Expected Less to return true, but was false")
  156. }
  157. if ((*randomToken)(big.NewInt(42))).Less((*randomToken)(big.NewInt(41))) {
  158. t.Errorf("Expected Less to return false, but was true")
  159. }
  160. }
  161. type intToken int
  162. func (i intToken) String() string {
  163. return strconv.Itoa(int(i))
  164. }
  165. func (i intToken) Less(token token) bool {
  166. return i < token.(intToken)
  167. }
  168. // Test of the token ring implementation based on example at the start of this
  169. // page of documentation:
  170. // http://www.datastax.com/docs/0.8/cluster_architecture/partitioning
  171. func TestIntTokenRing(t *testing.T) {
  172. host0 := &HostInfo{}
  173. host25 := &HostInfo{}
  174. host50 := &HostInfo{}
  175. host75 := &HostInfo{}
  176. ring := &tokenRing{
  177. partitioner: nil,
  178. // these tokens and hosts are out of order to test sorting
  179. tokens: []token{
  180. intToken(0),
  181. intToken(50),
  182. intToken(75),
  183. intToken(25),
  184. },
  185. hosts: []*HostInfo{
  186. host0,
  187. host50,
  188. host75,
  189. host25,
  190. },
  191. }
  192. sort.Sort(ring)
  193. if ring.GetHostForToken(intToken(0)) != host0 {
  194. t.Error("Expected host 0 for token 0")
  195. }
  196. if ring.GetHostForToken(intToken(1)) != host25 {
  197. t.Error("Expected host 25 for token 1")
  198. }
  199. if ring.GetHostForToken(intToken(24)) != host25 {
  200. t.Error("Expected host 25 for token 24")
  201. }
  202. if ring.GetHostForToken(intToken(25)) != host25 {
  203. t.Error("Expected host 25 for token 25")
  204. }
  205. if ring.GetHostForToken(intToken(26)) != host50 {
  206. t.Error("Expected host 50 for token 26")
  207. }
  208. if ring.GetHostForToken(intToken(49)) != host50 {
  209. t.Error("Expected host 50 for token 49")
  210. }
  211. if ring.GetHostForToken(intToken(50)) != host50 {
  212. t.Error("Expected host 50 for token 50")
  213. }
  214. if ring.GetHostForToken(intToken(51)) != host75 {
  215. t.Error("Expected host 75 for token 51")
  216. }
  217. if ring.GetHostForToken(intToken(74)) != host75 {
  218. t.Error("Expected host 75 for token 74")
  219. }
  220. if ring.GetHostForToken(intToken(75)) != host75 {
  221. t.Error("Expected host 75 for token 75")
  222. }
  223. if ring.GetHostForToken(intToken(76)) != host0 {
  224. t.Error("Expected host 0 for token 76")
  225. }
  226. if ring.GetHostForToken(intToken(99)) != host0 {
  227. t.Error("Expected host 0 for token 99")
  228. }
  229. if ring.GetHostForToken(intToken(100)) != host0 {
  230. t.Error("Expected host 0 for token 100")
  231. }
  232. }
  233. // Test for the behavior of a nil pointer to tokenRing
  234. func TestNilTokenRing(t *testing.T) {
  235. var ring *tokenRing = nil
  236. if ring.GetHostForToken(nil) != nil {
  237. t.Error("Expected nil for nil token ring")
  238. }
  239. if ring.GetHostForPartitionKey(nil) != nil {
  240. t.Error("Expected nil for nil token ring")
  241. }
  242. }
  243. // Test of the recognition of the partitioner class
  244. func TestUnknownTokenRing(t *testing.T) {
  245. _, err := newTokenRing("UnknownPartitioner", nil)
  246. if err == nil {
  247. t.Error("Expected error for unknown partitioner value, but was nil")
  248. }
  249. }
  250. // Test of the tokenRing with the Murmur3Partitioner
  251. func TestMurmur3TokenRing(t *testing.T) {
  252. // Note, strings are parsed directly to int64, they are not murmur3 hashed
  253. var hosts []HostInfo = []HostInfo{
  254. HostInfo{
  255. Peer: "0",
  256. Tokens: []string{"0"},
  257. },
  258. HostInfo{
  259. Peer: "1",
  260. Tokens: []string{"25"},
  261. },
  262. HostInfo{
  263. Peer: "2",
  264. Tokens: []string{"50"},
  265. },
  266. HostInfo{
  267. Peer: "3",
  268. Tokens: []string{"75"},
  269. },
  270. }
  271. ring, err := newTokenRing("Murmur3Partitioner", hosts)
  272. if err != nil {
  273. t.Fatalf("Failed to create token ring due to error: %v", err)
  274. }
  275. p := murmur3Partitioner{}
  276. var actual *HostInfo
  277. actual = ring.GetHostForToken(p.ParseString("0"))
  278. if actual.Peer != "0" {
  279. t.Errorf("Expected peer 0 for token \"0\", but was %s", actual.Peer)
  280. }
  281. actual = ring.GetHostForToken(p.ParseString("25"))
  282. if actual.Peer != "1" {
  283. t.Errorf("Expected peer 1 for token \"25\", but was %s", actual.Peer)
  284. }
  285. actual = ring.GetHostForToken(p.ParseString("50"))
  286. if actual.Peer != "2" {
  287. t.Errorf("Expected peer 2 for token \"50\", but was %s", actual.Peer)
  288. }
  289. actual = ring.GetHostForToken(p.ParseString("75"))
  290. if actual.Peer != "3" {
  291. t.Errorf("Expected peer 3 for token \"01\", but was %s", actual.Peer)
  292. }
  293. actual = ring.GetHostForToken(p.ParseString("12"))
  294. if actual.Peer != "1" {
  295. t.Errorf("Expected peer 1 for token \"12\", but was %s", actual.Peer)
  296. }
  297. actual = ring.GetHostForToken(p.ParseString("24324545443332"))
  298. if actual.Peer != "0" {
  299. t.Errorf("Expected peer 0 for token \"24324545443332\", but was %s", actual.Peer)
  300. }
  301. }
  302. // Test of the tokenRing with the OrderedPartitioner
  303. func TestOrderedTokenRing(t *testing.T) {
  304. // Tokens here more or less are similar layout to the int tokens above due
  305. // to each numeric character translating to a consistently offset byte.
  306. var hosts []HostInfo = []HostInfo{
  307. HostInfo{
  308. Peer: "0",
  309. Tokens: []string{
  310. "00",
  311. },
  312. },
  313. HostInfo{
  314. Peer: "1",
  315. Tokens: []string{
  316. "25",
  317. },
  318. },
  319. HostInfo{
  320. Peer: "2",
  321. Tokens: []string{
  322. "50",
  323. },
  324. },
  325. HostInfo{
  326. Peer: "3",
  327. Tokens: []string{
  328. "75",
  329. },
  330. },
  331. }
  332. ring, err := newTokenRing("OrderedPartitioner", hosts)
  333. if err != nil {
  334. t.Fatalf("Failed to create token ring due to error: %v", err)
  335. }
  336. p := orderedPartitioner{}
  337. var actual *HostInfo
  338. actual = ring.GetHostForToken(p.ParseString("0"))
  339. if actual.Peer != "0" {
  340. t.Errorf("Expected peer 0 for token \"0\", but was %s", actual.Peer)
  341. }
  342. actual = ring.GetHostForToken(p.ParseString("25"))
  343. if actual.Peer != "1" {
  344. t.Errorf("Expected peer 1 for token \"25\", but was %s", actual.Peer)
  345. }
  346. actual = ring.GetHostForToken(p.ParseString("50"))
  347. if actual.Peer != "2" {
  348. t.Errorf("Expected peer 2 for token \"50\", but was %s", actual.Peer)
  349. }
  350. actual = ring.GetHostForToken(p.ParseString("75"))
  351. if actual.Peer != "3" {
  352. t.Errorf("Expected peer 3 for token \"01\", but was %s", actual.Peer)
  353. }
  354. actual = ring.GetHostForToken(p.ParseString("12"))
  355. if actual.Peer != "1" {
  356. t.Errorf("Expected peer 1 for token \"12\", but was %s", actual.Peer)
  357. }
  358. actual = ring.GetHostForToken(p.ParseString("24324545443332"))
  359. if actual.Peer != "1" {
  360. t.Errorf("Expected peer 1 for token \"24324545443332\", but was %s", actual.Peer)
  361. }
  362. }
  363. // Test of the tokenRing with the RandomPartitioner
  364. func TestRandomTokenRing(t *testing.T) {
  365. // String tokens are parsed into big.Int in base 10
  366. var hosts []HostInfo = []HostInfo{
  367. HostInfo{
  368. Peer: "0",
  369. Tokens: []string{
  370. "00",
  371. },
  372. },
  373. HostInfo{
  374. Peer: "1",
  375. Tokens: []string{
  376. "25",
  377. },
  378. },
  379. HostInfo{
  380. Peer: "2",
  381. Tokens: []string{
  382. "50",
  383. },
  384. },
  385. HostInfo{
  386. Peer: "3",
  387. Tokens: []string{
  388. "75",
  389. },
  390. },
  391. }
  392. ring, err := newTokenRing("RandomPartitioner", hosts)
  393. if err != nil {
  394. t.Fatalf("Failed to create token ring due to error: %v", err)
  395. }
  396. p := randomPartitioner{}
  397. var actual *HostInfo
  398. actual = ring.GetHostForToken(p.ParseString("0"))
  399. if actual.Peer != "0" {
  400. t.Errorf("Expected peer 0 for token \"0\", but was %s", actual.Peer)
  401. }
  402. actual = ring.GetHostForToken(p.ParseString("25"))
  403. if actual.Peer != "1" {
  404. t.Errorf("Expected peer 1 for token \"25\", but was %s", actual.Peer)
  405. }
  406. actual = ring.GetHostForToken(p.ParseString("50"))
  407. if actual.Peer != "2" {
  408. t.Errorf("Expected peer 2 for token \"50\", but was %s", actual.Peer)
  409. }
  410. actual = ring.GetHostForToken(p.ParseString("75"))
  411. if actual.Peer != "3" {
  412. t.Errorf("Expected peer 3 for token \"01\", but was %s", actual.Peer)
  413. }
  414. actual = ring.GetHostForToken(p.ParseString("12"))
  415. if actual.Peer != "1" {
  416. t.Errorf("Expected peer 1 for token \"12\", but was %s", actual.Peer)
  417. }
  418. actual = ring.GetHostForToken(p.ParseString("24324545443332"))
  419. if actual.Peer != "0" {
  420. t.Errorf("Expected peer 0 for token \"24324545443332\", but was %s", actual.Peer)
  421. }
  422. }