11/*
2- Copyright 2023 Tim Ebert.
2+ Copyright 2025 Tim Ebert.
33
44Licensed under the Apache License, Version 2.0 (the "License");
55you may not use this file except in compliance with the License.
@@ -14,63 +14,78 @@ See the License for the specific language governing permissions and
1414limitations under the License.
1515*/
1616
17- package consistenthash
17+ package consistenthash_test
1818
1919import (
20- "fmt"
21- "math"
22- "testing"
20+ "strings"
21+
22+ . "github.com/onsi/ginkgo/v2"
23+ . "github.com/onsi/gomega"
24+
25+ . "github.com/timebertt/kubernetes-controller-sharding/pkg/sharding/consistenthash"
2326)
2427
25- func TestDistribution (t * testing.T ) {
26- ring := New (DefaultHash , DefaultTokensPerNode )
27-
28- hosts := generateHostnames (10 )
29- dist := make (map [string ]float64 , len (hosts ))
30- ring .AddNodes (hosts ... )
31- for _ , host := range hosts {
32- dist [host ] = 0
33- }
34-
35- // fmt.Println("Virtual Nodes:")
36- last := ring .tokens [len (ring .tokens )- 1 ]
37- for _ , token := range ring .tokens {
38- node := ring .tokenToNode [token ]
39- percentage := float64 (token - last ) / math .MaxUint64
40- dist [node ] += percentage
41-
42- // fmt.Printf("\t%016x (%.5f): %.5f -> %s\n", token, float64(token)/math.MaxUint64, percentage, node)
43- last = token
44- }
45-
46- fmt .Println ("Nodes distribution:" )
47- for _ , host := range hosts {
48- fmt .Printf ("\t %s: %.5f\n " , host , dist [host ])
49- }
50- }
51-
52- func generateHostnames (n int ) []string {
53- hosts := make ([]string , n )
54- for i := range hosts {
55- host := fmt .Sprintf ("10.42.0.%d" , i )
56- hosts [i ] = host
57- }
58- return hosts
59- }
60-
61- func benchmarkRing (nodes int , tokensPerNode int , b * testing.B ) {
62- hosts := generateHostnames (nodes )
63- b .ResetTimer ()
64-
65- for n := 0 ; n < b .N ; n ++ {
66- ring := New (DefaultHash , tokensPerNode , hosts ... )
67- ring .Hash ("Website.webhosting.timebertt.dev/project-foo/homepage" )
68- }
69- }
70-
71- func BenchmarkRing3_100 (b * testing.B ) { benchmarkRing (3 , 100 , b ) }
72- func BenchmarkRing3_1000 (b * testing.B ) { benchmarkRing (3 , 1000 , b ) }
73- func BenchmarkRing5_100 (b * testing.B ) { benchmarkRing (5 , 100 , b ) }
74- func BenchmarkRing5_1000 (b * testing.B ) { benchmarkRing (5 , 1000 , b ) }
75- func BenchmarkRing10_100 (b * testing.B ) { benchmarkRing (10 , 100 , b ) }
76- func BenchmarkRing10_1000 (b * testing.B ) { benchmarkRing (10 , 1000 , b ) }
28+ var _ = Describe ("Ring" , func () {
29+ Describe ("#New" , func () {
30+ It ("should initialize a new Ring" , func () {
31+ ring := New (nil , 0 , "foo" )
32+ Expect (ring ).NotTo (BeNil ())
33+ Expect (ring .IsEmpty ()).To (BeFalse ())
34+ })
35+ })
36+
37+ Describe ("#IsEmpty" , func () {
38+ It ("should true if there are no nodes" , func () {
39+ ring := New (nil , 0 )
40+ Expect (ring .IsEmpty ()).To (BeTrue ())
41+ ring .AddNodes ("foo" )
42+ Expect (ring .IsEmpty ()).To (BeFalse ())
43+ })
44+ })
45+
46+ Describe ("#Hash" , func () {
47+ It ("should use the configured hash function" , func () {
48+ ring := New (func (data string ) uint64 {
49+ if strings .HasPrefix (data , "foo" ) {
50+ // map all foo* nodes and keys to 1
51+ return 1
52+ }
53+ return 2
54+ }, 1 , "foo" , "bar" )
55+
56+ Expect (ring .Hash ("foo" )).To (Equal ("foo" ))
57+ Expect (ring .Hash ("bar" )).To (Equal ("bar" ))
58+ Expect (ring .Hash ("baz" )).To (Equal ("bar" ))
59+ })
60+
61+ It ("should use the default hash function" , func () {
62+ ring := New (nil , 0 , "foo" , "bar" )
63+
64+ Expect (ring .Hash ("1" )).NotTo (Equal (ring .Hash ("10" )))
65+ })
66+
67+ It ("should return the empty string if there are no nodes" , func () {
68+ ring := New (nil , 0 )
69+
70+ Expect (ring .Hash ("foo" )).To (BeEmpty ())
71+ })
72+
73+ It ("should return the first node when walking the whole ring" , func () {
74+ ring := New (func (data string ) uint64 {
75+ if strings .HasPrefix (data , "foo" ) {
76+ // map all foo* nodes and keys to 1
77+ return 1
78+ }
79+ if strings .HasPrefix (data , "bar" ) {
80+ // map all bar* nodes and keys to 1
81+ return 2
82+ }
83+ return 3
84+ }, 1 , "foo" , "bar" )
85+
86+ Expect (ring .Hash ("foo" )).To (Equal ("foo" ))
87+ Expect (ring .Hash ("bar" )).To (Equal ("bar" ))
88+ Expect (ring .Hash ("baz" )).To (Equal ("foo" ))
89+ })
90+ })
91+ })
0 commit comments