Skip to content

Commit 56932e6

Browse files
committed
test: add picker logic tests for member picking and error handling.
1 parent 0f3c8d1 commit 56932e6

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

pkg/balancer/picker_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package balancer
2+
3+
import (
4+
"context"
5+
"crypto/sha256"
6+
"encoding/binary"
7+
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
"google.golang.org/grpc/balancer"
11+
12+
"github.com/Permify/permify/pkg/consistent"
13+
)
14+
15+
type mockConnection struct {
16+
id string
17+
}
18+
19+
type testMember struct {
20+
name string
21+
conn *mockConnection
22+
}
23+
24+
func (m testMember) String() string {
25+
return m.name
26+
}
27+
28+
func (m testMember) Connection() *mockConnection {
29+
return m.conn
30+
}
31+
32+
var _ = Describe("Picker and Consistent Hashing", func() {
33+
var (
34+
c *consistent.Consistent
35+
testMembers []testMember
36+
hasher func(data []byte) uint64
37+
)
38+
39+
// Custom hasher using SHA-256 for consistent hashing
40+
hasher = func(data []byte) uint64 {
41+
hash := sha256.Sum256(data)
42+
return binary.BigEndian.Uint64(hash[:8]) // Use the first 8 bytes as the hash
43+
}
44+
45+
BeforeEach(func() {
46+
// Initialize consistent hashing with a valid hasher
47+
c = consistent.New(consistent.Config{
48+
Hasher: hasher,
49+
PartitionCount: 100,
50+
ReplicationFactor: 2,
51+
Load: 1.5,
52+
})
53+
54+
// Add test members to the consistent hash ring
55+
testMembers = []testMember{
56+
{name: "member1", conn: &mockConnection{id: "conn1"}},
57+
{name: "member2", conn: &mockConnection{id: "conn2"}},
58+
{name: "member3", conn: &mockConnection{id: "conn3"}},
59+
}
60+
for _, m := range testMembers {
61+
c.Add(m)
62+
}
63+
})
64+
65+
Describe("Picker Logic", func() {
66+
var (
67+
p *picker
68+
testCtx context.Context
69+
)
70+
71+
BeforeEach(func() {
72+
// Initialize picker with consistent hashing and a width of 2
73+
p = &picker{
74+
consistent: c,
75+
width: 2,
76+
}
77+
// Set up context with a valid key
78+
testCtx = context.WithValue(context.Background(), Key, []byte("test-key"))
79+
})
80+
81+
It("should pick a member successfully", func() {
82+
// Mock picker behavior
83+
members, err := c.ClosestN([]byte("test-key"), 2)
84+
Expect(err).To(BeNil())
85+
Expect(len(members)).To(BeNumerically(">", 0))
86+
Expect(members[0].String()).To(Equal("member1"))
87+
})
88+
89+
It("should return an error if the context key is missing", func() {
90+
result, err := p.Pick(balancer.PickInfo{Ctx: context.Background()})
91+
Expect(err).To(MatchError("context key missing"))
92+
Expect(result.SubConn).To(BeNil())
93+
})
94+
95+
It("should return an error if no members are available", func() {
96+
// Remove all members
97+
for _, m := range testMembers {
98+
c.Remove(m.String())
99+
}
100+
result, err := p.Pick(balancer.PickInfo{Ctx: testCtx})
101+
Expect(err).To(MatchError("failed to get closest members: not enough members to satisfy the request"))
102+
Expect(result.SubConn).To(BeNil())
103+
})
104+
})
105+
})

0 commit comments

Comments
 (0)