ffcf41b85a
Introduce `AddUserToOrganization`, `RemoveAPIKey`, and `RemoveOrganization` commands to enhance organization management. Implement validation for user addition and API key removal. Update GraphQL schema to support new mutations and add caching for the new events, ensuring that organizations and their relationships are accurately represented in the cache.
255 lines
6.7 KiB
Go
255 lines
6.7 KiB
Go
package domain
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
|
|
)
|
|
|
|
func TestOrganizationAdded_UpdateOrganization(t *testing.T) {
|
|
event := &OrganizationAdded{
|
|
BaseEvent: eventsourced.BaseEvent{
|
|
EventTime: eventsourced.EventTime{
|
|
Time: time.Now(),
|
|
},
|
|
},
|
|
Name: "Test Organization",
|
|
Initiator: "user@example.com",
|
|
}
|
|
|
|
org := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
|
}
|
|
|
|
event.UpdateOrganization(org)
|
|
|
|
assert.Equal(t, "Test Organization", org.Name)
|
|
assert.Equal(t, []string{"user@example.com"}, org.Users)
|
|
assert.Equal(t, "user@example.com", org.CreatedBy)
|
|
assert.Equal(t, "user@example.com", org.ChangedBy)
|
|
assert.Equal(t, event.When(), org.CreatedAt)
|
|
assert.Equal(t, event.When(), org.ChangedAt)
|
|
}
|
|
|
|
func TestUserAddedToOrganization_UpdateOrganization(t *testing.T) {
|
|
event := &UserAddedToOrganization{
|
|
BaseEvent: eventsourced.BaseEvent{
|
|
EventTime: eventsourced.EventTime{
|
|
Time: time.Now(),
|
|
},
|
|
},
|
|
UserId: "new-user@example.com",
|
|
Initiator: "admin@example.com",
|
|
}
|
|
|
|
org := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
|
Users: []string{"existing-user@example.com"},
|
|
}
|
|
|
|
event.UpdateOrganization(org)
|
|
|
|
assert.Len(t, org.Users, 2)
|
|
assert.Contains(t, org.Users, "existing-user@example.com")
|
|
assert.Contains(t, org.Users, "new-user@example.com")
|
|
assert.Equal(t, "admin@example.com", org.ChangedBy)
|
|
assert.Equal(t, event.When(), org.ChangedAt)
|
|
}
|
|
|
|
func TestUserAddedToOrganization_UpdateOrganization_DuplicateUser(t *testing.T) {
|
|
event := &UserAddedToOrganization{
|
|
BaseEvent: eventsourced.BaseEvent{
|
|
EventTime: eventsourced.EventTime{
|
|
Time: time.Now(),
|
|
},
|
|
},
|
|
UserId: "existing-user@example.com",
|
|
Initiator: "admin@example.com",
|
|
}
|
|
|
|
org := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
|
Users: []string{"existing-user@example.com"},
|
|
ChangedBy: "previous-admin@example.com",
|
|
}
|
|
originalChangedBy := org.ChangedBy
|
|
originalChangedAt := org.ChangedAt
|
|
|
|
event.UpdateOrganization(org)
|
|
|
|
// User should not be added twice
|
|
assert.Len(t, org.Users, 1)
|
|
assert.Equal(t, "existing-user@example.com", org.Users[0])
|
|
|
|
// ChangedBy and ChangedAt should NOT be updated when user already exists (idempotent)
|
|
assert.Equal(t, originalChangedBy, org.ChangedBy)
|
|
assert.Equal(t, originalChangedAt, org.ChangedAt)
|
|
}
|
|
|
|
func TestAPIKeyRemoved_UpdateOrganization(t *testing.T) {
|
|
event := &APIKeyRemoved{
|
|
BaseEvent: eventsourced.BaseEvent{
|
|
EventTime: eventsourced.EventTime{
|
|
Time: time.Now(),
|
|
},
|
|
},
|
|
KeyName: "production-key",
|
|
Initiator: "admin@example.com",
|
|
}
|
|
|
|
org := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
|
APIKeys: []APIKey{
|
|
{Name: "dev-key", Key: "hashed-key-1"},
|
|
{Name: "production-key", Key: "hashed-key-2"},
|
|
{Name: "staging-key", Key: "hashed-key-3"},
|
|
},
|
|
}
|
|
|
|
event.UpdateOrganization(org)
|
|
|
|
assert.Len(t, org.APIKeys, 2)
|
|
assert.Equal(t, "dev-key", org.APIKeys[0].Name)
|
|
assert.Equal(t, "staging-key", org.APIKeys[1].Name)
|
|
assert.Equal(t, "admin@example.com", org.ChangedBy)
|
|
assert.Equal(t, event.When(), org.ChangedAt)
|
|
}
|
|
|
|
func TestAPIKeyRemoved_UpdateOrganization_KeyNotFound(t *testing.T) {
|
|
event := &APIKeyRemoved{
|
|
BaseEvent: eventsourced.BaseEvent{
|
|
EventTime: eventsourced.EventTime{
|
|
Time: time.Now(),
|
|
},
|
|
},
|
|
KeyName: "non-existent-key",
|
|
Initiator: "admin@example.com",
|
|
}
|
|
|
|
org := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
|
APIKeys: []APIKey{
|
|
{Name: "dev-key", Key: "hashed-key-1"},
|
|
{Name: "production-key", Key: "hashed-key-2"},
|
|
},
|
|
}
|
|
|
|
event.UpdateOrganization(org)
|
|
|
|
// No keys should be removed
|
|
assert.Len(t, org.APIKeys, 2)
|
|
assert.Equal(t, "dev-key", org.APIKeys[0].Name)
|
|
assert.Equal(t, "production-key", org.APIKeys[1].Name)
|
|
|
|
// But metadata should still be updated
|
|
assert.Equal(t, "admin@example.com", org.ChangedBy)
|
|
assert.Equal(t, event.When(), org.ChangedAt)
|
|
}
|
|
|
|
func TestAPIKeyRemoved_UpdateOrganization_OnlyKey(t *testing.T) {
|
|
event := &APIKeyRemoved{
|
|
BaseEvent: eventsourced.BaseEvent{
|
|
EventTime: eventsourced.EventTime{
|
|
Time: time.Now(),
|
|
},
|
|
},
|
|
KeyName: "only-key",
|
|
Initiator: "admin@example.com",
|
|
}
|
|
|
|
org := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
|
APIKeys: []APIKey{
|
|
{Name: "only-key", Key: "hashed-key"},
|
|
},
|
|
}
|
|
|
|
event.UpdateOrganization(org)
|
|
|
|
// All keys should be removed
|
|
assert.Len(t, org.APIKeys, 0)
|
|
assert.Equal(t, "admin@example.com", org.ChangedBy)
|
|
assert.Equal(t, event.When(), org.ChangedAt)
|
|
}
|
|
|
|
func TestOrganizationRemoved_UpdateOrganization(t *testing.T) {
|
|
event := &OrganizationRemoved{
|
|
BaseEvent: eventsourced.BaseEvent{
|
|
EventTime: eventsourced.EventTime{
|
|
Time: time.Now(),
|
|
},
|
|
},
|
|
Initiator: "admin@example.com",
|
|
}
|
|
|
|
org := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
|
Name: "Test Organization",
|
|
Users: []string{"user1@example.com", "user2@example.com"},
|
|
APIKeys: []APIKey{
|
|
{Name: "key1", Key: "hashed-key-1"},
|
|
},
|
|
CreatedBy: "creator@example.com",
|
|
CreatedAt: time.Now().Add(-24 * time.Hour),
|
|
}
|
|
|
|
event.UpdateOrganization(org)
|
|
|
|
// Organization data remains (soft delete), but metadata is updated
|
|
assert.Equal(t, "Test Organization", org.Name)
|
|
assert.Len(t, org.Users, 2)
|
|
assert.Len(t, org.APIKeys, 1)
|
|
|
|
// Metadata should be updated to reflect removal
|
|
assert.Equal(t, "admin@example.com", org.ChangedBy)
|
|
assert.Equal(t, event.When(), org.ChangedAt)
|
|
}
|
|
|
|
func TestAPIKeyAdded_EnrichFromAggregate(t *testing.T) {
|
|
orgId := "org-123"
|
|
aggregate := &Organization{
|
|
BaseAggregate: eventsourced.BaseAggregateFromString(orgId),
|
|
}
|
|
|
|
event := &APIKeyAdded{
|
|
Name: "test-key",
|
|
Key: "hashed-key",
|
|
Refs: []string{"main"},
|
|
Read: true,
|
|
Publish: false,
|
|
Initiator: "user@example.com",
|
|
}
|
|
|
|
event.EnrichFromAggregate(aggregate)
|
|
|
|
assert.Equal(t, orgId, event.OrganizationId)
|
|
}
|
|
|
|
func TestSubGraphUpdated_Event(t *testing.T) {
|
|
// Verify SubGraphUpdated event structure
|
|
url := "http://service.example.com"
|
|
wsUrl := "ws://service.example.com"
|
|
|
|
event := &SubGraphUpdated{
|
|
OrganizationId: "org-123",
|
|
Ref: "main",
|
|
Service: "users-service",
|
|
Url: &url,
|
|
WSUrl: &wsUrl,
|
|
Sdl: "type Query { user: User }",
|
|
Initiator: "system",
|
|
}
|
|
|
|
require.NotNil(t, event)
|
|
assert.Equal(t, "org-123", event.OrganizationId)
|
|
assert.Equal(t, "main", event.Ref)
|
|
assert.Equal(t, "users-service", event.Service)
|
|
assert.Equal(t, url, *event.Url)
|
|
assert.Equal(t, wsUrl, *event.WSUrl)
|
|
assert.Equal(t, "type Query { user: User }", event.Sdl)
|
|
assert.Equal(t, "system", event.Initiator)
|
|
}
|