token_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. "fmt"
  8. "math/big"
  9. "net"
  10. "sort"
  11. "strconv"
  12. "testing"
  13. )
  14. // Tests of the murmur3Patitioner
  15. func TestMurmur3Partitioner(t *testing.T) {
  16. token := murmur3Partitioner{}.ParseString("-1053604476080545076")
  17. if "-1053604476080545076" != token.String() {
  18. t.Errorf("Expected '-1053604476080545076' but was '%s'", token)
  19. }
  20. // at least verify that the partitioner
  21. // doesn't return nil
  22. pk, _ := marshalInt(nil, 1)
  23. token = murmur3Partitioner{}.Hash(pk)
  24. if token == nil {
  25. t.Fatal("token was nil")
  26. }
  27. }
  28. // Tests of the murmur3Token
  29. func TestMurmur3Token(t *testing.T) {
  30. if murmur3Token(42).Less(murmur3Token(42)) {
  31. t.Errorf("Expected Less to return false, but was true")
  32. }
  33. if !murmur3Token(-42).Less(murmur3Token(42)) {
  34. t.Errorf("Expected Less to return true, but was false")
  35. }
  36. if murmur3Token(42).Less(murmur3Token(-42)) {
  37. t.Errorf("Expected Less to return false, but was true")
  38. }
  39. }
  40. // Tests of the orderedPartitioner
  41. func TestOrderedPartitioner(t *testing.T) {
  42. // at least verify that the partitioner
  43. // doesn't return nil
  44. p := orderedPartitioner{}
  45. pk, _ := marshalInt(nil, 1)
  46. token := p.Hash(pk)
  47. if token == nil {
  48. t.Fatal("token was nil")
  49. }
  50. str := token.String()
  51. parsedToken := p.ParseString(str)
  52. if !bytes.Equal([]byte(token.(orderedToken)), []byte(parsedToken.(orderedToken))) {
  53. t.Errorf("Failed to convert to and from a string %s expected %x but was %x",
  54. str,
  55. []byte(token.(orderedToken)),
  56. []byte(parsedToken.(orderedToken)),
  57. )
  58. }
  59. }
  60. // Tests of the orderedToken
  61. func TestOrderedToken(t *testing.T) {
  62. if orderedToken([]byte{0, 0, 4, 2}).Less(orderedToken([]byte{0, 0, 4, 2})) {
  63. t.Errorf("Expected Less to return false, but was true")
  64. }
  65. if !orderedToken([]byte{0, 0, 3}).Less(orderedToken([]byte{0, 0, 4, 2})) {
  66. t.Errorf("Expected Less to return true, but was false")
  67. }
  68. if orderedToken([]byte{0, 0, 4, 2}).Less(orderedToken([]byte{0, 0, 3})) {
  69. t.Errorf("Expected Less to return false, but was true")
  70. }
  71. }
  72. // Tests of the randomPartitioner
  73. func TestRandomPartitioner(t *testing.T) {
  74. // at least verify that the partitioner
  75. // doesn't return nil
  76. p := randomPartitioner{}
  77. pk, _ := marshalInt(nil, 1)
  78. token := p.Hash(pk)
  79. if token == nil {
  80. t.Fatal("token was nil")
  81. }
  82. str := token.String()
  83. parsedToken := p.ParseString(str)
  84. if (*big.Int)(token.(*randomToken)).Cmp((*big.Int)(parsedToken.(*randomToken))) != 0 {
  85. t.Errorf("Failed to convert to and from a string %s expected %v but was %v",
  86. str,
  87. token,
  88. parsedToken,
  89. )
  90. }
  91. }
  92. func TestRandomPartitionerMatchesReference(t *testing.T) {
  93. // example taken from datastax python driver
  94. // >>> from cassandra.metadata import MD5Token
  95. // >>> MD5Token.hash_fn("test")
  96. // 12707736894140473154801792860916528374L
  97. var p randomPartitioner
  98. expect := "12707736894140473154801792860916528374"
  99. actual := p.Hash([]byte("test")).String()
  100. if actual != expect {
  101. t.Errorf("expected random partitioner to generate tokens in the same way as the reference"+
  102. " python client. Expected %s, but got %s", expect, actual)
  103. }
  104. }
  105. // Tests of the randomToken
  106. func TestRandomToken(t *testing.T) {
  107. if ((*randomToken)(big.NewInt(42))).Less((*randomToken)(big.NewInt(42))) {
  108. t.Errorf("Expected Less to return false, but was true")
  109. }
  110. if !((*randomToken)(big.NewInt(41))).Less((*randomToken)(big.NewInt(42))) {
  111. t.Errorf("Expected Less to return true, but was false")
  112. }
  113. if ((*randomToken)(big.NewInt(42))).Less((*randomToken)(big.NewInt(41))) {
  114. t.Errorf("Expected Less to return false, but was true")
  115. }
  116. }
  117. type intToken int
  118. func (i intToken) String() string { return strconv.Itoa(int(i)) }
  119. func (i intToken) Less(token token) bool { return i < token.(intToken) }
  120. // Test of the token ring implementation based on example at the start of this
  121. // page of documentation:
  122. // http://www.datastax.com/docs/0.8/cluster_architecture/partitioning
  123. func TestTokenRing_Int(t *testing.T) {
  124. host0 := &HostInfo{}
  125. host25 := &HostInfo{}
  126. host50 := &HostInfo{}
  127. host75 := &HostInfo{}
  128. ring := &tokenRing{
  129. partitioner: nil,
  130. // these tokens and hosts are out of order to test sorting
  131. tokens: []hostToken{
  132. {intToken(0), host0},
  133. {intToken(50), host50},
  134. {intToken(75), host75},
  135. {intToken(25), host25},
  136. },
  137. }
  138. sort.Sort(ring)
  139. if host, endToken := ring.GetHostForToken(intToken(0)); host != host0 || endToken != intToken(0) {
  140. t.Error("Expected host 0 for token 0")
  141. }
  142. if host, endToken := ring.GetHostForToken(intToken(1)); host != host25 || endToken != intToken(25) {
  143. t.Error("Expected host 25 for token 1")
  144. }
  145. if host, endToken := ring.GetHostForToken(intToken(24)); host != host25 || endToken != intToken(25) {
  146. t.Error("Expected host 25 for token 24")
  147. }
  148. if host, endToken := ring.GetHostForToken(intToken(25)); host != host25 || endToken != intToken(25) {
  149. t.Error("Expected host 25 for token 25")
  150. }
  151. if host, endToken := ring.GetHostForToken(intToken(26)); host != host50 || endToken != intToken(50) {
  152. t.Error("Expected host 50 for token 26")
  153. }
  154. if host, endToken := ring.GetHostForToken(intToken(49)); host != host50 || endToken != intToken(50) {
  155. t.Error("Expected host 50 for token 49")
  156. }
  157. if host, endToken := ring.GetHostForToken(intToken(50)); host != host50 || endToken != intToken(50) {
  158. t.Error("Expected host 50 for token 50")
  159. }
  160. if host, endToken := ring.GetHostForToken(intToken(51)); host != host75 || endToken != intToken(75) {
  161. t.Error("Expected host 75 for token 51")
  162. }
  163. if host, endToken := ring.GetHostForToken(intToken(74)); host != host75 || endToken != intToken(75) {
  164. t.Error("Expected host 75 for token 74")
  165. }
  166. if host, endToken := ring.GetHostForToken(intToken(75)); host != host75 || endToken != intToken(75) {
  167. t.Error("Expected host 75 for token 75")
  168. }
  169. if host, endToken := ring.GetHostForToken(intToken(76)); host != host0 || endToken != intToken(0) {
  170. t.Error("Expected host 0 for token 76")
  171. }
  172. if host, endToken := ring.GetHostForToken(intToken(99)); host != host0 || endToken != intToken(0) {
  173. t.Error("Expected host 0 for token 99")
  174. }
  175. if host, endToken := ring.GetHostForToken(intToken(100)); host != host0 || endToken != intToken(0) {
  176. t.Error("Expected host 0 for token 100")
  177. }
  178. }
  179. // Test for the behavior of a nil pointer to tokenRing
  180. func TestTokenRing_Nil(t *testing.T) {
  181. var ring *tokenRing = nil
  182. if host, endToken := ring.GetHostForToken(nil); host != nil || endToken != nil {
  183. t.Error("Expected nil for nil token ring")
  184. }
  185. }
  186. // Test of the recognition of the partitioner class
  187. func TestTokenRing_UnknownPartition(t *testing.T) {
  188. _, err := newTokenRing("UnknownPartitioner", nil)
  189. if err == nil {
  190. t.Error("Expected error for unknown partitioner value, but was nil")
  191. }
  192. }
  193. func hostsForTests(n int) []*HostInfo {
  194. hosts := make([]*HostInfo, n)
  195. for i := 0; i < n; i++ {
  196. host := &HostInfo{
  197. connectAddress: net.IPv4(1, 1, 1, byte(n)),
  198. tokens: []string{fmt.Sprintf("%d", n)},
  199. }
  200. hosts[i] = host
  201. }
  202. return hosts
  203. }
  204. // Test of the tokenRing with the Murmur3Partitioner
  205. func TestTokenRing_Murmur3(t *testing.T) {
  206. // Note, strings are parsed directly to int64, they are not murmur3 hashed
  207. hosts := hostsForTests(4)
  208. ring, err := newTokenRing("Murmur3Partitioner", hosts)
  209. if err != nil {
  210. t.Fatalf("Failed to create token ring due to error: %v", err)
  211. }
  212. p := murmur3Partitioner{}
  213. for _, host := range hosts {
  214. actual, _ := ring.GetHostForToken(p.ParseString(host.tokens[0]))
  215. if !actual.ConnectAddress().Equal(host.ConnectAddress()) {
  216. t.Errorf("Expected address %v for token %q, but was %v", host.ConnectAddress(),
  217. host.tokens[0], actual.ConnectAddress())
  218. }
  219. }
  220. actual, _ := ring.GetHostForToken(p.ParseString("12"))
  221. if !actual.ConnectAddress().Equal(hosts[1].ConnectAddress()) {
  222. t.Errorf("Expected address 1 for token \"12\", but was %s", actual.ConnectAddress())
  223. }
  224. actual, _ = ring.GetHostForToken(p.ParseString("24324545443332"))
  225. if !actual.ConnectAddress().Equal(hosts[0].ConnectAddress()) {
  226. t.Errorf("Expected address 0 for token \"24324545443332\", but was %s", actual.ConnectAddress())
  227. }
  228. }
  229. // Test of the tokenRing with the OrderedPartitioner
  230. func TestTokenRing_Ordered(t *testing.T) {
  231. // Tokens here more or less are similar layout to the int tokens above due
  232. // to each numeric character translating to a consistently offset byte.
  233. hosts := hostsForTests(4)
  234. ring, err := newTokenRing("OrderedPartitioner", hosts)
  235. if err != nil {
  236. t.Fatalf("Failed to create token ring due to error: %v", err)
  237. }
  238. p := orderedPartitioner{}
  239. var actual *HostInfo
  240. for _, host := range hosts {
  241. actual, _ := ring.GetHostForToken(p.ParseString(host.tokens[0]))
  242. if !actual.ConnectAddress().Equal(host.ConnectAddress()) {
  243. t.Errorf("Expected address %v for token %q, but was %v", host.ConnectAddress(),
  244. host.tokens[0], actual.ConnectAddress())
  245. }
  246. }
  247. actual, _ = ring.GetHostForToken(p.ParseString("12"))
  248. if !actual.peer.Equal(hosts[1].peer) {
  249. t.Errorf("Expected address 1 for token \"12\", but was %s", actual.ConnectAddress())
  250. }
  251. actual, _ = ring.GetHostForToken(p.ParseString("24324545443332"))
  252. if !actual.ConnectAddress().Equal(hosts[1].ConnectAddress()) {
  253. t.Errorf("Expected address 1 for token \"24324545443332\", but was %s", actual.ConnectAddress())
  254. }
  255. }
  256. // Test of the tokenRing with the RandomPartitioner
  257. func TestTokenRing_Random(t *testing.T) {
  258. // String tokens are parsed into big.Int in base 10
  259. hosts := hostsForTests(4)
  260. ring, err := newTokenRing("RandomPartitioner", hosts)
  261. if err != nil {
  262. t.Fatalf("Failed to create token ring due to error: %v", err)
  263. }
  264. p := randomPartitioner{}
  265. var actual *HostInfo
  266. for _, host := range hosts {
  267. actual, _ := ring.GetHostForToken(p.ParseString(host.tokens[0]))
  268. if !actual.ConnectAddress().Equal(host.ConnectAddress()) {
  269. t.Errorf("Expected address %v for token %q, but was %v", host.ConnectAddress(),
  270. host.tokens[0], actual.ConnectAddress())
  271. }
  272. }
  273. actual, _ = ring.GetHostForToken(p.ParseString("12"))
  274. if !actual.peer.Equal(hosts[1].peer) {
  275. t.Errorf("Expected address 1 for token \"12\", but was %s", actual.ConnectAddress())
  276. }
  277. actual, _ = ring.GetHostForToken(p.ParseString("24324545443332"))
  278. if !actual.ConnectAddress().Equal(hosts[0].ConnectAddress()) {
  279. t.Errorf("Expected address 1 for token \"24324545443332\", but was %s", actual.ConnectAddress())
  280. }
  281. }