Files
zitadel/internal/query/projection/domains_test.go

356 lines
10 KiB
Go
Raw Normal View History

package projection
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/org"
)
func TestDomainsProjection_reduceOrgDomainAdded(t *testing.T) {
projection := &domainsProjection{}
event := &org.DomainAddedEvent{
BaseEvent: &eventstore.BaseEvent{
Agg: &eventstore.Aggregate{
ID: "org-id",
InstanceID: "instance-id",
Type: org.AggregateType,
ResourceOwner: "instance-id",
},
CreationDate: time.Now(),
},
Domain: "test.example.com",
}
stmt, err := projection.reduceOrgDomainAdded(event)
require.NoError(t, err)
assert.NotNil(t, stmt)
createStmt, ok := stmt.(*handler.CreateStatement)
require.True(t, ok)
// Verify the columns being set
expectedColumns := map[string]interface{}{
DomainsInstanceIDCol: "instance-id",
DomainsOrgIDCol: "org-id",
DomainsDomainCol: "test.example.com",
DomainsIsVerifiedCol: false,
DomainsIsPrimaryCol: false,
DomainsValidationTypeCol: domain.OrgDomainValidationTypeUnspecified,
DomainsCreatedAtCol: event.CreationDate(),
DomainsUpdatedAtCol: event.CreationDate(),
}
assert.Len(t, createStmt.Cols, len(expectedColumns))
for i, col := range createStmt.Cols {
switch col.Name {
case DomainsInstanceIDCol:
assert.Equal(t, "instance-id", col.Value)
case DomainsOrgIDCol:
assert.Equal(t, "org-id", col.Value)
case DomainsDomainCol:
assert.Equal(t, "test.example.com", col.Value)
case DomainsIsVerifiedCol:
assert.Equal(t, false, col.Value)
case DomainsIsPrimaryCol:
assert.Equal(t, false, col.Value)
case DomainsValidationTypeCol:
assert.Equal(t, domain.OrgDomainValidationTypeUnspecified, col.Value)
case DomainsCreatedAtCol, DomainsUpdatedAtCol:
assert.Equal(t, event.CreationDate(), col.Value)
default:
t.Errorf("Unexpected column: %s at index %d", col.Name, i)
}
}
}
func TestDomainsProjection_reduceOrgDomainVerified(t *testing.T) {
projection := &domainsProjection{}
event := &org.DomainVerifiedEvent{
BaseEvent: &eventstore.BaseEvent{
Agg: &eventstore.Aggregate{
ID: "org-id",
InstanceID: "instance-id",
Type: org.AggregateType,
ResourceOwner: "instance-id",
},
CreationDate: time.Now(),
},
Domain: "test.example.com",
}
stmt, err := projection.reduceOrgDomainVerified(event)
require.NoError(t, err)
assert.NotNil(t, stmt)
updateStmt, ok := stmt.(*handler.UpdateStatement)
require.True(t, ok)
// Verify update columns
assert.Len(t, updateStmt.Cols, 2)
assert.Equal(t, DomainsUpdatedAtCol, updateStmt.Cols[0].Name)
assert.Equal(t, event.CreationDate(), updateStmt.Cols[0].Value)
assert.Equal(t, DomainsIsVerifiedCol, updateStmt.Cols[1].Name)
assert.Equal(t, true, updateStmt.Cols[1].Value)
// Verify conditions
assert.Len(t, updateStmt.Conditions, 4)
conditionMap := make(map[string]interface{})
for _, cond := range updateStmt.Conditions {
conditionMap[cond.Name] = cond.Value
}
assert.Equal(t, "instance-id", conditionMap[DomainsInstanceIDCol])
assert.Equal(t, "org-id", conditionMap[DomainsOrgIDCol])
assert.Equal(t, "test.example.com", conditionMap[DomainsDomainCol])
assert.Nil(t, conditionMap[DomainsDeletedAtCol])
}
func TestDomainsProjection_reduceOrgPrimaryDomainSet(t *testing.T) {
projection := &domainsProjection{}
event := &org.DomainPrimarySetEvent{
BaseEvent: &eventstore.BaseEvent{
Agg: &eventstore.Aggregate{
ID: "org-id",
InstanceID: "instance-id",
Type: org.AggregateType,
ResourceOwner: "instance-id",
},
CreationDate: time.Now(),
},
Domain: "test.example.com",
}
stmt, err := projection.reduceOrgPrimaryDomainSet(event)
require.NoError(t, err)
assert.NotNil(t, stmt)
multiStmt, ok := stmt.(*handler.MultiStatement)
require.True(t, ok)
// Should have 2 update statements: unset old primary, set new primary
assert.Len(t, multiStmt.Statements, 2)
// First statement: unset existing primary
unsetStmt, ok := multiStmt.Statements[0].(*handler.UpdateStatement)
require.True(t, ok)
assert.Len(t, unsetStmt.Cols, 2)
assert.Equal(t, DomainsUpdatedAtCol, unsetStmt.Cols[0].Name)
assert.Equal(t, DomainsIsPrimaryCol, unsetStmt.Cols[1].Name)
assert.Equal(t, false, unsetStmt.Cols[1].Value)
// Second statement: set new primary
setStmt, ok := multiStmt.Statements[1].(*handler.UpdateStatement)
require.True(t, ok)
assert.Len(t, setStmt.Cols, 2)
assert.Equal(t, DomainsUpdatedAtCol, setStmt.Cols[0].Name)
assert.Equal(t, DomainsIsPrimaryCol, setStmt.Cols[1].Name)
assert.Equal(t, true, setStmt.Cols[1].Value)
}
func TestDomainsProjection_reduceInstanceDomainAdded(t *testing.T) {
projection := &domainsProjection{}
event := &instance.DomainAddedEvent{
BaseEvent: &eventstore.BaseEvent{
Agg: &eventstore.Aggregate{
ID: "instance-id",
InstanceID: "instance-id",
Type: instance.AggregateType,
ResourceOwner: "instance-id",
},
CreationDate: time.Now(),
},
Domain: "instance.example.com",
Generated: false,
}
stmt, err := projection.reduceInstanceDomainAdded(event)
require.NoError(t, err)
assert.NotNil(t, stmt)
createStmt, ok := stmt.(*handler.CreateStatement)
require.True(t, ok)
// Verify the columns being set for instance domain
expectedColumns := map[string]interface{}{
DomainsInstanceIDCol: "instance-id",
DomainsOrgIDCol: nil, // Instance domains have no org_id
DomainsDomainCol: "instance.example.com",
DomainsIsVerifiedCol: true, // Instance domains are always verified
DomainsIsPrimaryCol: false,
DomainsValidationTypeCol: nil, // Instance domains have no validation type
DomainsCreatedAtCol: event.CreationDate(),
DomainsUpdatedAtCol: event.CreationDate(),
}
assert.Len(t, createStmt.Cols, len(expectedColumns))
for _, col := range createStmt.Cols {
switch col.Name {
case DomainsInstanceIDCol:
assert.Equal(t, "instance-id", col.Value)
case DomainsOrgIDCol:
assert.Nil(t, col.Value)
case DomainsDomainCol:
assert.Equal(t, "instance.example.com", col.Value)
case DomainsIsVerifiedCol:
assert.Equal(t, true, col.Value)
case DomainsIsPrimaryCol:
assert.Equal(t, false, col.Value)
case DomainsValidationTypeCol:
assert.Nil(t, col.Value)
case DomainsCreatedAtCol, DomainsUpdatedAtCol:
assert.Equal(t, event.CreationDate(), col.Value)
default:
t.Errorf("Unexpected column: %s", col.Name)
}
}
}
func TestDomainsProjection_reduceOrgDomainRemoved(t *testing.T) {
projection := &domainsProjection{}
event := &org.DomainRemovedEvent{
BaseEvent: &eventstore.BaseEvent{
Agg: &eventstore.Aggregate{
ID: "org-id",
InstanceID: "instance-id",
Type: org.AggregateType,
ResourceOwner: "instance-id",
},
CreationDate: time.Now(),
},
Domain: "test.example.com",
}
stmt, err := projection.reduceOrgDomainRemoved(event)
require.NoError(t, err)
assert.NotNil(t, stmt)
updateStmt, ok := stmt.(*handler.UpdateStatement)
require.True(t, ok)
// Should update updated_at and deleted_at
assert.Len(t, updateStmt.Cols, 2)
assert.Equal(t, DomainsUpdatedAtCol, updateStmt.Cols[0].Name)
assert.Equal(t, event.CreationDate(), updateStmt.Cols[0].Value)
assert.Equal(t, DomainsDeletedAtCol, updateStmt.Cols[1].Name)
assert.Equal(t, event.CreationDate(), updateStmt.Cols[1].Value)
// Verify conditions include instance, org, and domain
assert.Len(t, updateStmt.Conditions, 3)
conditionMap := make(map[string]interface{})
for _, cond := range updateStmt.Conditions {
conditionMap[cond.Name] = cond.Value
}
assert.Equal(t, "instance-id", conditionMap[DomainsInstanceIDCol])
assert.Equal(t, "org-id", conditionMap[DomainsOrgIDCol])
assert.Equal(t, "test.example.com", conditionMap[DomainsDomainCol])
}
func TestDomainsProjection_reduceOrgRemoved(t *testing.T) {
projection := &domainsProjection{}
event := &org.OrgRemovedEvent{
BaseEvent: &eventstore.BaseEvent{
Agg: &eventstore.Aggregate{
ID: "org-id",
InstanceID: "instance-id",
Type: org.AggregateType,
ResourceOwner: "instance-id",
},
CreationDate: time.Now(),
},
}
stmt, err := projection.reduceOrgRemoved(event)
require.NoError(t, err)
assert.NotNil(t, stmt)
updateStmt, ok := stmt.(*handler.UpdateStatement)
require.True(t, ok)
// Should update updated_at and deleted_at
assert.Len(t, updateStmt.Cols, 2)
assert.Equal(t, DomainsUpdatedAtCol, updateStmt.Cols[0].Name)
assert.Equal(t, event.CreationDate(), updateStmt.Cols[0].Value)
assert.Equal(t, DomainsDeletedAtCol, updateStmt.Cols[1].Name)
assert.Equal(t, event.CreationDate(), updateStmt.Cols[1].Value)
// Should soft delete all domains for the org
assert.Len(t, updateStmt.Conditions, 3)
conditionMap := make(map[string]interface{})
for _, cond := range updateStmt.Conditions {
conditionMap[cond.Name] = cond.Value
}
assert.Equal(t, "instance-id", conditionMap[DomainsInstanceIDCol])
assert.Equal(t, "org-id", conditionMap[DomainsOrgIDCol])
assert.Nil(t, conditionMap[DomainsDeletedAtCol]) // Only affect non-deleted domains
}
func TestDomainsProjection_reduceInstanceRemoved(t *testing.T) {
projection := &domainsProjection{}
event := &instance.InstanceRemovedEvent{
BaseEvent: &eventstore.BaseEvent{
Agg: &eventstore.Aggregate{
ID: "instance-id",
InstanceID: "instance-id",
Type: instance.AggregateType,
ResourceOwner: "instance-id",
},
CreationDate: time.Now(),
},
}
stmt, err := projection.reduceInstanceRemoved(event)
require.NoError(t, err)
assert.NotNil(t, stmt)
updateStmt, ok := stmt.(*handler.UpdateStatement)
require.True(t, ok)
// Should update updated_at and deleted_at
assert.Len(t, updateStmt.Cols, 2)
assert.Equal(t, DomainsUpdatedAtCol, updateStmt.Cols[0].Name)
assert.Equal(t, event.CreationDate(), updateStmt.Cols[0].Value)
assert.Equal(t, DomainsDeletedAtCol, updateStmt.Cols[1].Name)
assert.Equal(t, event.CreationDate(), updateStmt.Cols[1].Value)
// Should soft delete all domains for the instance
assert.Len(t, updateStmt.Conditions, 2)
conditionMap := make(map[string]interface{})
for _, cond := range updateStmt.Conditions {
conditionMap[cond.Name] = cond.Value
}
assert.Equal(t, "instance-id", conditionMap[DomainsInstanceIDCol])
assert.Nil(t, conditionMap[DomainsDeletedAtCol]) // Only affect non-deleted domains
}