Files
zitadel/internal/query/projection/group_users_test.go
Gayathri Vijayan ad8e8bf61f feat(group): manage users in user groups (#10940)
# Which Problems Are Solved

1. Adding users to user groups and removing users from user groups.
2. Searching for users in user groups by group IDs or user IDs

# How the Problems Are Solved

By adding:
1. The API definitions to manage users in users groups
3. The command-layer implementation of adding users/removing users
to/from user groups.
4. The projection table group_users1
5. Query-side implementation to search for users in user groups

# Additional Changes

1. Remove debug statements from unit tests.
2. Fix removal of groups when orgs are removed
3. Add unit tests for groups projection

# Additional Context

* Related to #9702 
* Follow-up for PRs 
  * https://github.com/zitadel/zitadel/pull/10455
  * https://github.com/zitadel/zitadel/pull/10758
  * https://github.com/zitadel/zitadel/pull/10853
2025-10-28 13:23:54 +00:00

178 lines
4.8 KiB
Go

package projection
import (
"testing"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/repository/group"
"github.com/zitadel/zitadel/internal/repository/org"
"github.com/zitadel/zitadel/internal/zerrors"
)
func Test_GroupUsersReduces(t *testing.T) {
t.Parallel()
type args struct {
event func(t *testing.T) eventstore.Event
}
tests := []struct {
name string
args args
reduce func(event eventstore.Event) (*handler.Statement, error)
want wantReduce
}{
{
name: "reduceGroupUsersAdded",
args: args{
event: getEvent(
testEvent(
group.GroupUsersAddedEventType,
group.AggregateType,
[]byte(
`{
"userIds": ["user-id-1", "user-id-2", "user-id-3"]
}`),
), eventstore.GenericEventMapper[group.GroupUsersAddedEvent],
),
},
reduce: (&groupUsersProjection{}).reduceGroupUsersAdded,
want: wantReduce{
aggregateType: eventstore.AggregateType("group"),
sequence: 15,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.group_users1 (group_id, user_id, resource_owner, instance_id, sequence, creation_date) VALUES ($1, $2, $3, $4, $5, $6)",
expectedArgs: []interface{}{
"agg-id",
"user-id-1",
"ro-id",
"instance-id",
uint64(15),
anyArg{},
},
},
{
expectedStmt: "INSERT INTO projections.group_users1 (group_id, user_id, resource_owner, instance_id, sequence, creation_date) VALUES ($1, $2, $3, $4, $5, $6)",
expectedArgs: []interface{}{
"agg-id",
"user-id-2",
"ro-id",
"instance-id",
uint64(15),
anyArg{},
},
},
{
expectedStmt: "INSERT INTO projections.group_users1 (group_id, user_id, resource_owner, instance_id, sequence, creation_date) VALUES ($1, $2, $3, $4, $5, $6)",
expectedArgs: []interface{}{
"agg-id",
"user-id-3",
"ro-id",
"instance-id",
uint64(15),
anyArg{},
},
},
},
},
},
},
{
name: "reduceGroupUsersRemoved",
args: args{
event: getEvent(
testEvent(
group.GroupUsersRemovedEventType,
group.AggregateType,
[]byte(
`{
"userIds": ["user-id-1", "user-id-2"]
}`),
), eventstore.GenericEventMapper[group.GroupUsersRemovedEvent],
),
},
reduce: (&groupUsersProjection{}).reduceGroupUsersRemoved,
want: wantReduce{
aggregateType: eventstore.AggregateType("group"),
sequence: 15,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.group_users1 WHERE (group_id = $1) AND (user_id = $2) AND (resource_owner = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{"agg-id", "user-id-1", "ro-id", "instance-id"},
},
{
expectedStmt: "DELETE FROM projections.group_users1 WHERE (group_id = $1) AND (user_id = $2) AND (resource_owner = $3) AND (instance_id = $4)",
expectedArgs: []interface{}{"agg-id", "user-id-2", "ro-id", "instance-id"},
},
},
},
},
},
{
name: "reduceGroupRemoved",
args: args{
event: getEvent(
testEvent(
group.GroupRemovedEventType,
group.AggregateType,
nil,
), eventstore.GenericEventMapper[group.GroupRemovedEvent],
),
},
reduce: (&groupUsersProjection{}).reduceGroupRemoved,
want: wantReduce{
aggregateType: eventstore.AggregateType("group"),
sequence: 15,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.group_users1 WHERE (group_id = $1) AND (resource_owner = $2) AND (instance_id = $3)",
expectedArgs: []interface{}{"agg-id", "ro-id", "instance-id"},
},
},
},
},
},
{
name: "reduceOwnerRemoved",
args: args{
event: getEvent(
testEvent(
org.OrgRemovedEventType,
org.AggregateType,
nil,
), org.OrgRemovedEventMapper,
),
},
reduce: (&groupUsersProjection{}).reduceOwnerRemoved,
want: wantReduce{
aggregateType: eventstore.AggregateType("org"),
sequence: 15,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.group_users1 WHERE (resource_owner = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{"agg-id", "instance-id"},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
event := baseEvent(t)
got, err := tt.reduce(event)
if ok := zerrors.IsErrorInvalidArgument(err); !ok {
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
}
event = tt.args.event(t)
got, err = tt.reduce(event)
assertReduce(t, got, err, GroupUsersProjectionTable, tt.want)
})
}
}