mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-30 00:04:25 +00:00
435 lines
11 KiB
Go
435 lines
11 KiB
Go
package websocketspec
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/bitechdev/ResolveSpec/pkg/common"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewSubscriptionManager(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
assert.NotNil(t, sm)
|
|
assert.NotNil(t, sm.subscriptions)
|
|
assert.NotNil(t, sm.entitySubscriptions)
|
|
assert.Equal(t, 0, sm.Count())
|
|
}
|
|
|
|
func TestSubscriptionManager_Subscribe(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
// Create a subscription
|
|
sub := sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
|
|
assert.NotNil(t, sub)
|
|
assert.Equal(t, "sub-1", sub.ID)
|
|
assert.Equal(t, "conn-1", sub.ConnectionID)
|
|
assert.Equal(t, "public", sub.Schema)
|
|
assert.Equal(t, "users", sub.Entity)
|
|
assert.True(t, sub.Active)
|
|
assert.Equal(t, 1, sm.Count())
|
|
}
|
|
|
|
func TestSubscriptionManager_Subscribe_WithOptions(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
options := &common.RequestOptions{
|
|
Filters: []common.FilterOption{
|
|
{Column: "status", Operator: "eq", Value: "active"},
|
|
},
|
|
}
|
|
|
|
sub := sm.Subscribe("sub-1", "conn-1", "public", "users", options)
|
|
|
|
assert.NotNil(t, sub)
|
|
assert.NotNil(t, sub.Options)
|
|
assert.Len(t, sub.Options.Filters, 1)
|
|
assert.Equal(t, "status", sub.Options.Filters[0].Column)
|
|
}
|
|
|
|
func TestSubscriptionManager_Subscribe_MultipleSubscriptions(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sub1 := sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
sub2 := sm.Subscribe("sub-2", "conn-1", "public", "posts", nil)
|
|
sub3 := sm.Subscribe("sub-3", "conn-2", "public", "users", nil)
|
|
|
|
assert.NotNil(t, sub1)
|
|
assert.NotNil(t, sub2)
|
|
assert.NotNil(t, sub3)
|
|
assert.Equal(t, 3, sm.Count())
|
|
}
|
|
|
|
func TestSubscriptionManager_Unsubscribe(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
assert.Equal(t, 1, sm.Count())
|
|
|
|
// Unsubscribe
|
|
ok := sm.Unsubscribe("sub-1")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 0, sm.Count())
|
|
}
|
|
|
|
func TestSubscriptionManager_Unsubscribe_NonExistent(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
ok := sm.Unsubscribe("non-existent")
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestSubscriptionManager_Unsubscribe_MultipleSubscriptions(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
sm.Subscribe("sub-2", "conn-1", "public", "posts", nil)
|
|
sm.Subscribe("sub-3", "conn-2", "public", "users", nil)
|
|
assert.Equal(t, 3, sm.Count())
|
|
|
|
// Unsubscribe one
|
|
ok := sm.Unsubscribe("sub-2")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 2, sm.Count())
|
|
|
|
// Verify the right subscription was removed
|
|
_, exists := sm.GetSubscription("sub-2")
|
|
assert.False(t, exists)
|
|
|
|
_, exists = sm.GetSubscription("sub-1")
|
|
assert.True(t, exists)
|
|
|
|
_, exists = sm.GetSubscription("sub-3")
|
|
assert.True(t, exists)
|
|
}
|
|
|
|
func TestSubscriptionManager_GetSubscription(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
|
|
// Get existing subscription
|
|
sub, exists := sm.GetSubscription("sub-1")
|
|
assert.True(t, exists)
|
|
assert.NotNil(t, sub)
|
|
assert.Equal(t, "sub-1", sub.ID)
|
|
}
|
|
|
|
func TestSubscriptionManager_GetSubscription_NonExistent(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sub, exists := sm.GetSubscription("non-existent")
|
|
assert.False(t, exists)
|
|
assert.Nil(t, sub)
|
|
}
|
|
|
|
func TestSubscriptionManager_GetSubscriptionsByEntity(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
sm.Subscribe("sub-2", "conn-2", "public", "users", nil)
|
|
sm.Subscribe("sub-3", "conn-1", "public", "posts", nil)
|
|
|
|
// Get subscriptions for users entity
|
|
subs := sm.GetSubscriptionsByEntity("public", "users")
|
|
assert.Len(t, subs, 2)
|
|
|
|
// Verify subscription IDs
|
|
ids := make([]string, len(subs))
|
|
for i, sub := range subs {
|
|
ids[i] = sub.ID
|
|
}
|
|
assert.Contains(t, ids, "sub-1")
|
|
assert.Contains(t, ids, "sub-2")
|
|
}
|
|
|
|
func TestSubscriptionManager_GetSubscriptionsByEntity_NoSchema(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "", "users", nil)
|
|
sm.Subscribe("sub-2", "conn-2", "", "users", nil)
|
|
|
|
// Get subscriptions without schema
|
|
subs := sm.GetSubscriptionsByEntity("", "users")
|
|
assert.Len(t, subs, 2)
|
|
}
|
|
|
|
func TestSubscriptionManager_GetSubscriptionsByEntity_NoResults(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
|
|
// Get subscriptions for non-existent entity
|
|
subs := sm.GetSubscriptionsByEntity("public", "posts")
|
|
assert.Nil(t, subs)
|
|
}
|
|
|
|
func TestSubscriptionManager_GetSubscriptionsByConnection(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
sm.Subscribe("sub-2", "conn-1", "public", "posts", nil)
|
|
sm.Subscribe("sub-3", "conn-2", "public", "users", nil)
|
|
|
|
// Get subscriptions for connection 1
|
|
subs := sm.GetSubscriptionsByConnection("conn-1")
|
|
assert.Len(t, subs, 2)
|
|
|
|
// Verify subscription IDs
|
|
ids := make([]string, len(subs))
|
|
for i, sub := range subs {
|
|
ids[i] = sub.ID
|
|
}
|
|
assert.Contains(t, ids, "sub-1")
|
|
assert.Contains(t, ids, "sub-2")
|
|
}
|
|
|
|
func TestSubscriptionManager_GetSubscriptionsByConnection_NoResults(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
|
|
// Get subscriptions for non-existent connection
|
|
subs := sm.GetSubscriptionsByConnection("conn-2")
|
|
assert.Empty(t, subs)
|
|
}
|
|
|
|
func TestSubscriptionManager_Count(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
assert.Equal(t, 0, sm.Count())
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
assert.Equal(t, 1, sm.Count())
|
|
|
|
sm.Subscribe("sub-2", "conn-1", "public", "posts", nil)
|
|
assert.Equal(t, 2, sm.Count())
|
|
|
|
sm.Unsubscribe("sub-1")
|
|
assert.Equal(t, 1, sm.Count())
|
|
|
|
sm.Unsubscribe("sub-2")
|
|
assert.Equal(t, 0, sm.Count())
|
|
}
|
|
|
|
func TestSubscriptionManager_CountForEntity(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
sm.Subscribe("sub-2", "conn-2", "public", "users", nil)
|
|
sm.Subscribe("sub-3", "conn-1", "public", "posts", nil)
|
|
|
|
assert.Equal(t, 2, sm.CountForEntity("public", "users"))
|
|
assert.Equal(t, 1, sm.CountForEntity("public", "posts"))
|
|
assert.Equal(t, 0, sm.CountForEntity("public", "orders"))
|
|
}
|
|
|
|
func TestSubscriptionManager_UnsubscribeUpdatesEntityIndex(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
sm.Subscribe("sub-1", "conn-1", "public", "users", nil)
|
|
sm.Subscribe("sub-2", "conn-2", "public", "users", nil)
|
|
assert.Equal(t, 2, sm.CountForEntity("public", "users"))
|
|
|
|
// Unsubscribe one
|
|
sm.Unsubscribe("sub-1")
|
|
assert.Equal(t, 1, sm.CountForEntity("public", "users"))
|
|
|
|
// Unsubscribe the other
|
|
sm.Unsubscribe("sub-2")
|
|
assert.Equal(t, 0, sm.CountForEntity("public", "users"))
|
|
}
|
|
|
|
func TestSubscription_MatchesFilters_NoFilters(t *testing.T) {
|
|
sub := &Subscription{
|
|
ID: "sub-1",
|
|
ConnectionID: "conn-1",
|
|
Schema: "public",
|
|
Entity: "users",
|
|
Options: nil,
|
|
Active: true,
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"id": 1,
|
|
"name": "John",
|
|
"status": "active",
|
|
}
|
|
|
|
// Should match when no filters are specified
|
|
assert.True(t, sub.MatchesFilters(data))
|
|
}
|
|
|
|
func TestSubscription_MatchesFilters_WithFilters(t *testing.T) {
|
|
sub := &Subscription{
|
|
ID: "sub-1",
|
|
ConnectionID: "conn-1",
|
|
Schema: "public",
|
|
Entity: "users",
|
|
Options: &common.RequestOptions{
|
|
Filters: []common.FilterOption{
|
|
{Column: "status", Operator: "eq", Value: "active"},
|
|
},
|
|
},
|
|
Active: true,
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"id": 1,
|
|
"name": "John",
|
|
"status": "active",
|
|
}
|
|
|
|
// Current implementation returns true for all data
|
|
// This test documents the expected behavior
|
|
assert.True(t, sub.MatchesFilters(data))
|
|
}
|
|
|
|
func TestSubscription_MatchesFilters_EmptyFiltersArray(t *testing.T) {
|
|
sub := &Subscription{
|
|
ID: "sub-1",
|
|
ConnectionID: "conn-1",
|
|
Schema: "public",
|
|
Entity: "users",
|
|
Options: &common.RequestOptions{
|
|
Filters: []common.FilterOption{},
|
|
},
|
|
Active: true,
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"id": 1,
|
|
"name": "John",
|
|
}
|
|
|
|
// Should match when filters array is empty
|
|
assert.True(t, sub.MatchesFilters(data))
|
|
}
|
|
|
|
func TestMakeEntityKey(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
schema string
|
|
entity string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "With schema",
|
|
schema: "public",
|
|
entity: "users",
|
|
expected: "public.users",
|
|
},
|
|
{
|
|
name: "Without schema",
|
|
schema: "",
|
|
entity: "users",
|
|
expected: "users",
|
|
},
|
|
{
|
|
name: "Different schema",
|
|
schema: "custom",
|
|
entity: "posts",
|
|
expected: "custom.posts",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := makeEntityKey(tt.schema, tt.entity)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionManager_ConcurrentOperations(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
// This test verifies that concurrent operations don't cause race conditions
|
|
// Run with: go test -race
|
|
|
|
done := make(chan bool)
|
|
|
|
// Goroutine 1: Subscribe
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
sm.Subscribe("sub-"+string(rune(i)), "conn-1", "public", "users", nil)
|
|
}
|
|
done <- true
|
|
}()
|
|
|
|
// Goroutine 2: Get subscriptions
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
sm.GetSubscriptionsByEntity("public", "users")
|
|
}
|
|
done <- true
|
|
}()
|
|
|
|
// Goroutine 3: Count
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
sm.Count()
|
|
}
|
|
done <- true
|
|
}()
|
|
|
|
// Wait for all goroutines
|
|
<-done
|
|
<-done
|
|
<-done
|
|
}
|
|
|
|
func TestSubscriptionManager_CompleteLifecycle(t *testing.T) {
|
|
sm := NewSubscriptionManager()
|
|
|
|
// Create subscriptions
|
|
options := &common.RequestOptions{
|
|
Filters: []common.FilterOption{
|
|
{Column: "status", Operator: "eq", Value: "active"},
|
|
},
|
|
}
|
|
|
|
sub1 := sm.Subscribe("sub-1", "conn-1", "public", "users", options)
|
|
require.NotNil(t, sub1)
|
|
assert.Equal(t, 1, sm.Count())
|
|
|
|
sub2 := sm.Subscribe("sub-2", "conn-1", "public", "posts", nil)
|
|
require.NotNil(t, sub2)
|
|
assert.Equal(t, 2, sm.Count())
|
|
|
|
// Get by entity
|
|
userSubs := sm.GetSubscriptionsByEntity("public", "users")
|
|
assert.Len(t, userSubs, 1)
|
|
assert.Equal(t, "sub-1", userSubs[0].ID)
|
|
|
|
// Get by connection
|
|
connSubs := sm.GetSubscriptionsByConnection("conn-1")
|
|
assert.Len(t, connSubs, 2)
|
|
|
|
// Get specific subscription
|
|
sub, exists := sm.GetSubscription("sub-1")
|
|
assert.True(t, exists)
|
|
assert.Equal(t, "sub-1", sub.ID)
|
|
assert.NotNil(t, sub.Options)
|
|
|
|
// Count by entity
|
|
assert.Equal(t, 1, sm.CountForEntity("public", "users"))
|
|
assert.Equal(t, 1, sm.CountForEntity("public", "posts"))
|
|
|
|
// Unsubscribe
|
|
ok := sm.Unsubscribe("sub-1")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 1, sm.Count())
|
|
assert.Equal(t, 0, sm.CountForEntity("public", "users"))
|
|
|
|
// Verify subscription is gone
|
|
_, exists = sm.GetSubscription("sub-1")
|
|
assert.False(t, exists)
|
|
|
|
// Unsubscribe second subscription
|
|
ok = sm.Unsubscribe("sub-2")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 0, sm.Count())
|
|
}
|