mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-31 08:44:25 +00:00
257 lines
5.5 KiB
Go
257 lines
5.5 KiB
Go
package mqttspec
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestNewClient(t *testing.T) {
|
|
client := NewClient("client-123", "user@example.com", nil)
|
|
|
|
assert.Equal(t, "client-123", client.ID)
|
|
assert.Equal(t, "user@example.com", client.Username)
|
|
assert.NotNil(t, client.subscriptions)
|
|
assert.NotNil(t, client.metadata)
|
|
assert.NotNil(t, client.ctx)
|
|
assert.NotNil(t, client.cancel)
|
|
}
|
|
|
|
func TestClient_Metadata(t *testing.T) {
|
|
client := NewClient("client-123", "user", nil)
|
|
|
|
// Set metadata
|
|
client.SetMetadata("user_id", 456)
|
|
client.SetMetadata("tenant_id", "tenant-abc")
|
|
client.SetMetadata("roles", []string{"admin", "user"})
|
|
|
|
// Get metadata
|
|
userID, exists := client.GetMetadata("user_id")
|
|
assert.True(t, exists)
|
|
assert.Equal(t, 456, userID)
|
|
|
|
tenantID, exists := client.GetMetadata("tenant_id")
|
|
assert.True(t, exists)
|
|
assert.Equal(t, "tenant-abc", tenantID)
|
|
|
|
roles, exists := client.GetMetadata("roles")
|
|
assert.True(t, exists)
|
|
assert.Equal(t, []string{"admin", "user"}, roles)
|
|
|
|
// Non-existent key
|
|
_, exists = client.GetMetadata("nonexistent")
|
|
assert.False(t, exists)
|
|
}
|
|
|
|
func TestClient_Subscriptions(t *testing.T) {
|
|
client := NewClient("client-123", "user", nil)
|
|
|
|
// Create mock subscription
|
|
sub := &Subscription{
|
|
ID: "sub-1",
|
|
ConnectionID: "client-123",
|
|
Schema: "public",
|
|
Entity: "users",
|
|
Active: true,
|
|
}
|
|
|
|
// Add subscription
|
|
client.AddSubscription(sub)
|
|
|
|
// Get subscription
|
|
retrieved, exists := client.GetSubscription("sub-1")
|
|
assert.True(t, exists)
|
|
assert.Equal(t, "sub-1", retrieved.ID)
|
|
|
|
// Remove subscription
|
|
client.RemoveSubscription("sub-1")
|
|
|
|
// Verify removed
|
|
_, exists = client.GetSubscription("sub-1")
|
|
assert.False(t, exists)
|
|
}
|
|
|
|
func TestClient_Close(t *testing.T) {
|
|
client := NewClient("client-123", "user", nil)
|
|
|
|
// Add some subscriptions
|
|
client.AddSubscription(&Subscription{ID: "sub-1"})
|
|
client.AddSubscription(&Subscription{ID: "sub-2"})
|
|
|
|
// Close client
|
|
client.Close()
|
|
|
|
// Verify subscriptions cleared
|
|
client.subMu.RLock()
|
|
assert.Empty(t, client.subscriptions)
|
|
client.subMu.RUnlock()
|
|
|
|
// Verify context cancelled
|
|
select {
|
|
case <-client.ctx.Done():
|
|
// Context was cancelled
|
|
default:
|
|
t.Fatal("Context should be cancelled after Close()")
|
|
}
|
|
}
|
|
|
|
func TestNewClientManager(t *testing.T) {
|
|
cm := NewClientManager(context.Background())
|
|
|
|
assert.NotNil(t, cm)
|
|
assert.NotNil(t, cm.clients)
|
|
assert.Equal(t, 0, cm.Count())
|
|
}
|
|
|
|
func TestClientManager_Register(t *testing.T) {
|
|
cm := NewClientManager(context.Background())
|
|
defer cm.Shutdown()
|
|
|
|
client := cm.Register("client-1", "user@example.com", nil)
|
|
|
|
assert.NotNil(t, client)
|
|
assert.Equal(t, "client-1", client.ID)
|
|
assert.Equal(t, "user@example.com", client.Username)
|
|
assert.Equal(t, 1, cm.Count())
|
|
}
|
|
|
|
func TestClientManager_Unregister(t *testing.T) {
|
|
cm := NewClientManager(context.Background())
|
|
defer cm.Shutdown()
|
|
|
|
cm.Register("client-1", "user1", nil)
|
|
assert.Equal(t, 1, cm.Count())
|
|
|
|
cm.Unregister("client-1")
|
|
assert.Equal(t, 0, cm.Count())
|
|
}
|
|
|
|
func TestClientManager_GetClient(t *testing.T) {
|
|
cm := NewClientManager(context.Background())
|
|
defer cm.Shutdown()
|
|
|
|
cm.Register("client-1", "user1", nil)
|
|
|
|
// Get existing client
|
|
client, exists := cm.GetClient("client-1")
|
|
assert.True(t, exists)
|
|
assert.NotNil(t, client)
|
|
assert.Equal(t, "client-1", client.ID)
|
|
|
|
// Get non-existent client
|
|
_, exists = cm.GetClient("nonexistent")
|
|
assert.False(t, exists)
|
|
}
|
|
|
|
func TestClientManager_MultipleClients(t *testing.T) {
|
|
cm := NewClientManager(context.Background())
|
|
defer cm.Shutdown()
|
|
|
|
cm.Register("client-1", "user1", nil)
|
|
cm.Register("client-2", "user2", nil)
|
|
cm.Register("client-3", "user3", nil)
|
|
|
|
assert.Equal(t, 3, cm.Count())
|
|
|
|
cm.Unregister("client-2")
|
|
assert.Equal(t, 2, cm.Count())
|
|
|
|
// Verify correct client was removed
|
|
_, exists := cm.GetClient("client-2")
|
|
assert.False(t, exists)
|
|
|
|
_, exists = cm.GetClient("client-1")
|
|
assert.True(t, exists)
|
|
|
|
_, exists = cm.GetClient("client-3")
|
|
assert.True(t, exists)
|
|
}
|
|
|
|
func TestClientManager_Shutdown(t *testing.T) {
|
|
cm := NewClientManager(context.Background())
|
|
|
|
cm.Register("client-1", "user1", nil)
|
|
cm.Register("client-2", "user2", nil)
|
|
assert.Equal(t, 2, cm.Count())
|
|
|
|
cm.Shutdown()
|
|
|
|
// All clients should be removed
|
|
assert.Equal(t, 0, cm.Count())
|
|
|
|
// Context should be cancelled
|
|
select {
|
|
case <-cm.ctx.Done():
|
|
// Context was cancelled
|
|
default:
|
|
t.Fatal("Context should be cancelled after Shutdown()")
|
|
}
|
|
}
|
|
|
|
func TestClientManager_ConcurrentOperations(t *testing.T) {
|
|
cm := NewClientManager(context.Background())
|
|
defer cm.Shutdown()
|
|
|
|
// This test verifies that concurrent operations don't cause race conditions
|
|
// Run with: go test -race
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Goroutine 1: Register clients
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 100; i++ {
|
|
cm.Register("client-"+string(rune(i)), "user", nil)
|
|
}
|
|
}()
|
|
|
|
// Goroutine 2: Get clients
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 100; i++ {
|
|
cm.GetClient("client-" + string(rune(i)))
|
|
}
|
|
}()
|
|
|
|
// Goroutine 3: Count
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 100; i++ {
|
|
cm.Count()
|
|
}
|
|
}()
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func TestClient_ConcurrentMetadata(t *testing.T) {
|
|
client := NewClient("client-123", "user", nil)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Concurrent writes
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 100; i++ {
|
|
client.SetMetadata("key1", i)
|
|
}
|
|
}()
|
|
|
|
// Concurrent reads
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 100; i++ {
|
|
client.GetMetadata("key1")
|
|
}
|
|
}()
|
|
|
|
wg.Wait()
|
|
}
|