From 9ddbc80e81191319489aace57030ee6a812de4fa Mon Sep 17 00:00:00 2001 From: Silvan Date: Tue, 16 Nov 2021 09:44:56 +0100 Subject: [PATCH] fix(queries): project grant and role prepare funcs (#2659) * chore(queries): test suite for prepare stmt funcs * test(queries): prepare project funcs * refactor: add comments * test: simlify expected sql, added possibility to add args to expected queries * test(queries): prepare funcs in org * chore(backend): correct modules * test(queries): org domain prepare funcs * test: correct name * refactor: file name * refactor: add table to login policy columns * chore(prepare_test): only add row to result if columns * test(queries): login policy prepare funcs * chore: add comments for configs * test(queries): prepare idp funcs * fix(queries): add table to password complexity policy cols * test(queries): password complexity policy prepare funcs * fix(queries): add table to password age policy cols * test(queries): password age policy prepare func * fix(queries): set cols on lockout policy * test(queries): lockout policy prepare funs * fix(queries): set table on privacy policy cols * test(queries): privacy policy prepare funcs * fix(queries): set table on org iam policy cols * fix(queries): correct table in org iam policy cols * test(queries): org iam policy prepare funcs * test(queries): prepare project grant funcs * refactor(queries): prepareProjectRoleQuery as func * test(queries): prepare project role funcs * test(queries): project grant check for nulls in joins * fix(queries): allow null values in project grant --- internal/query/project_grant.go | 78 ++- internal/query/project_grant_test.go | 836 +++++++++++++++++++++++++++ internal/query/project_role.go | 6 +- internal/query/project_role_test.go | 312 ++++++++++ 4 files changed, 1200 insertions(+), 32 deletions(-) create mode 100644 internal/query/project_grant_test.go create mode 100644 internal/query/project_role_test.go diff --git a/internal/query/project_grant.go b/internal/query/project_grant.go index a2913463c7..7dfeb4d964 100644 --- a/internal/query/project_grant.go +++ b/internal/query/project_grant.go @@ -255,20 +255,25 @@ func prepareProjectGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*ProjectGrant LeftJoin(join(resourceOwnerIDColumn, ProjectGrantColumnResourceOwner)). LeftJoin(join(grantedOrgIDColumn, ProjectGrantColumnGrantedOrgID)), func(row *sql.Row) (*ProjectGrant, error) { - p := new(ProjectGrant) + grant := new(ProjectGrant) + var ( + projectName sql.NullString + orgName sql.NullString + resourceOwnerName sql.NullString + ) err := row.Scan( - &p.ProjectID, - &p.GrantID, - &p.CreationDate, - &p.ChangeDate, - &p.ResourceOwner, - &p.State, - &p.Sequence, - &p.ProjectName, - &p.GrantedOrgID, - &p.OrgName, - &p.GrantedRoleKeys, - &p.ResourceOwnerName, + &grant.ProjectID, + &grant.GrantID, + &grant.CreationDate, + &grant.ChangeDate, + &grant.ResourceOwner, + &grant.State, + &grant.Sequence, + &projectName, + &grant.GrantedOrgID, + &orgName, + &grant.GrantedRoleKeys, + &resourceOwnerName, ) if err != nil { if errs.Is(err, sql.ErrNoRows) { @@ -276,7 +281,12 @@ func prepareProjectGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*ProjectGrant } return nil, errors.ThrowInternal(err, "QUERY-w9fsH", "Errors.Internal") } - return p, nil + + grant.ProjectName = projectName.String + grant.ResourceOwnerName = resourceOwnerName.String + grant.OrgName = orgName.String + + return grant, nil } } @@ -305,28 +315,38 @@ func prepareProjectGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*ProjectGra LeftJoin(join(grantedOrgIDColumn, ProjectGrantColumnGrantedOrgID)), func(rows *sql.Rows) (*ProjectGrants, error) { projects := make([]*ProjectGrant, 0) - var count uint64 + var ( + count uint64 + projectName sql.NullString + orgName sql.NullString + resourceOwnerName sql.NullString + ) for rows.Next() { - project := new(ProjectGrant) + grant := new(ProjectGrant) err := rows.Scan( - &project.ProjectID, - &project.GrantID, - &project.CreationDate, - &project.ChangeDate, - &project.ResourceOwner, - &project.State, - &project.Sequence, - &project.ProjectName, - &project.GrantedOrgID, - &project.OrgName, - &project.GrantedRoleKeys, - &project.ResourceOwnerName, + &grant.ProjectID, + &grant.GrantID, + &grant.CreationDate, + &grant.ChangeDate, + &grant.ResourceOwner, + &grant.State, + &grant.Sequence, + &projectName, + &grant.GrantedOrgID, + &orgName, + &grant.GrantedRoleKeys, + &resourceOwnerName, &count, ) if err != nil { return nil, err } - projects = append(projects, project) + + grant.ProjectName = projectName.String + grant.ResourceOwnerName = resourceOwnerName.String + grant.OrgName = orgName.String + + projects = append(projects, grant) } if err := rows.Close(); err != nil { diff --git a/internal/query/project_grant_test.go b/internal/query/project_grant_test.go new file mode 100644 index 0000000000..6ed75fb992 --- /dev/null +++ b/internal/query/project_grant_test.go @@ -0,0 +1,836 @@ +package query + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "regexp" + "testing" + + "github.com/caos/zitadel/internal/domain" + errs "github.com/caos/zitadel/internal/errors" + "github.com/lib/pq" +) + +func Test_ProjectGrantPrepares(t *testing.T) { + type want struct { + sqlExpectations sqlExpectation + err checkErr + } + tests := []struct { + name string + prepare interface{} + want want + object interface{} + }{ + { + name: "prepareProjectGrantsQuery no result", + prepare: prepareProjectGrantsQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name,`+ + ` COUNT(*) OVER () `+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + nil, + nil, + ), + }, + object: &ProjectGrants{ProjectGrants: []*ProjectGrant{}}, + }, + { + name: "prepareProjectGrantsQuery one result", + prepare: prepareProjectGrantsQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name,`+ + ` COUNT(*) OVER ()`+ + ` FROM zitadel.projections.project_grants`+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id`+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + "count", + }, + [][]driver.Value{ + { + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + "org-name", + pq.StringArray{"role-key"}, + "ro-name", + }, + }, + ), + }, + object: &ProjectGrants{ + SearchResponse: SearchResponse{ + Count: 1, + }, + ProjectGrants: []*ProjectGrant{ + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + }, + }, + }, + { + name: "prepareProjectGrantsQuery no project", + prepare: prepareProjectGrantsQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name,`+ + ` COUNT(*) OVER () `+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + "count", + }, + [][]driver.Value{ + { + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + nil, + "org-id", + "org-name", + pq.StringArray{"role-key"}, + "ro-name", + }, + }, + ), + }, + object: &ProjectGrants{ + SearchResponse: SearchResponse{ + Count: 1, + }, + ProjectGrants: []*ProjectGrant{ + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + }, + }, + }, + { + name: "prepareProjectGrantsQuery no org", + prepare: prepareProjectGrantsQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name,`+ + ` COUNT(*) OVER () `+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + "count", + }, + [][]driver.Value{ + { + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + nil, + pq.StringArray{"role-key"}, + "ro-name", + }, + }, + ), + }, + object: &ProjectGrants{ + SearchResponse: SearchResponse{ + Count: 1, + }, + ProjectGrants: []*ProjectGrant{ + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + }, + }, + }, + { + name: "prepareProjectGrantsQuery no resource owner", + prepare: prepareProjectGrantsQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name,`+ + ` COUNT(*) OVER () `+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + "count", + }, + [][]driver.Value{ + { + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + "org-name", + pq.StringArray{"role-key"}, + nil, + }, + }, + ), + }, + object: &ProjectGrants{ + SearchResponse: SearchResponse{ + Count: 1, + }, + ProjectGrants: []*ProjectGrant{ + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "", + }, + }, + }, + }, + { + name: "prepareProjectGrantsQuery multiple result", + prepare: prepareProjectGrantsQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name,`+ + ` COUNT(*) OVER () `+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + "count", + }, + [][]driver.Value{ + { + "project-id", + "grant-id-1", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + "org-name", + pq.StringArray{"role-key"}, + "ro-name", + }, + { + "project-id", + "grant-id-2", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + "org-name", + pq.StringArray{"role-key"}, + "ro-name", + }, + }, + ), + }, + object: &ProjectGrants{ + SearchResponse: SearchResponse{ + Count: 2, + }, + ProjectGrants: []*ProjectGrant{ + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id-1", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id-2", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + }, + }, + }, + { + name: "prepareProjectGrantsQuery sql err", + prepare: prepareProjectGrantsQuery, + want: want{ + sqlExpectations: mockQueryErr( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name,`+ + ` COUNT(*) OVER () `+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + sql.ErrConnDone, + ), + err: func(err error) (error, bool) { + if !errors.Is(err, sql.ErrConnDone) { + return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false + } + return nil, true + }, + }, + object: nil, + }, + { + name: "prepareProjectGrantQuery no result", + prepare: prepareProjectGrantQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name`+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + nil, + nil, + ), + err: func(err error) (error, bool) { + if !errs.IsNotFound(err) { + return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false + } + return nil, true + }, + }, + object: (*ProjectGrant)(nil), + }, + { + name: "prepareProjectGrantQuery found", + prepare: prepareProjectGrantQuery, + want: want{ + sqlExpectations: mockQuery( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name`+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + }, + []driver.Value{ + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + "org-name", + pq.StringArray{"role-key"}, + "ro-name", + }, + ), + }, + object: &ProjectGrant{ + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + }, + { + name: "prepareProjectGrantQuery no org", + prepare: prepareProjectGrantQuery, + want: want{ + sqlExpectations: mockQuery( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name`+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + }, + []driver.Value{ + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + nil, + pq.StringArray{"role-key"}, + "ro-name", + }, + ), + }, + object: &ProjectGrant{ + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + }, + { + name: "prepareProjectGrantQuery no resource owner", + prepare: prepareProjectGrantQuery, + want: want{ + sqlExpectations: mockQuery( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name`+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + }, + []driver.Value{ + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + "project-name", + "org-id", + "org-name", + pq.StringArray{"role-key"}, + nil, + }, + ), + }, + object: &ProjectGrant{ + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "project-name", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "", + }, + }, + { + name: "prepareProjectGrantQuery no project", + prepare: prepareProjectGrantQuery, + want: want{ + sqlExpectations: mockQuery( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name`+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + []string{ + "project_id", + "grant_id", + "creation_date", + "change_date", + "resource_owner", + "state", + "sequence", + "name", + "granted_org_id", + "name", + "granted_role_keys", + "name", + }, + []driver.Value{ + "project-id", + "grant-id", + testNow, + testNow, + "ro", + domain.ProjectGrantStateActive, + 20211111, + nil, + "org-id", + "org-name", + pq.StringArray{"role-key"}, + "ro-name", + }, + ), + }, + object: &ProjectGrant{ + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + GrantID: "grant-id", + State: domain.ProjectGrantStateActive, + ProjectName: "", + GrantedOrgID: "org-id", + OrgName: "org-name", + GrantedRoleKeys: pq.StringArray{"role-key"}, + ResourceOwnerName: "ro-name", + }, + }, + { + name: "prepareProjectGrantQuery sql err", + prepare: prepareProjectGrantQuery, + want: want{ + sqlExpectations: mockQueryErr( + regexp.QuoteMeta(` SELECT zitadel.projections.project_grants.project_id,`+ + ` zitadel.projections.project_grants.grant_id,`+ + ` zitadel.projections.project_grants.creation_date,`+ + ` zitadel.projections.project_grants.change_date,`+ + ` zitadel.projections.project_grants.resource_owner,`+ + ` zitadel.projections.project_grants.state,`+ + ` zitadel.projections.project_grants.sequence,`+ + ` zitadel.projections.projects.name,`+ + ` zitadel.projections.project_grants.granted_org_id,`+ + ` o.name,`+ + ` zitadel.projections.project_grants.granted_role_keys,`+ + ` r.name`+ + ` FROM zitadel.projections.project_grants `+ + ` LEFT JOIN zitadel.projections.projects ON zitadel.projections.project_grants.project_id = zitadel.projections.projects.id `+ + ` LEFT JOIN zitadel.projections.orgs as r ON zitadel.projections.project_grants.resource_owner = r.id`+ + ` LEFT JOIN zitadel.projections.orgs as o ON zitadel.projections.project_grants.granted_org_id = o.id`), + sql.ErrConnDone, + ), + err: func(err error) (error, bool) { + if !errors.Is(err, sql.ErrConnDone) { + return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false + } + return nil, true + }, + }, + object: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err) + }) + } +} diff --git a/internal/query/project_role.go b/internal/query/project_role.go index 7acbd62efe..7b972b7f61 100644 --- a/internal/query/project_role.go +++ b/internal/query/project_role.go @@ -96,7 +96,7 @@ func (q *Queries) ExistsProjectRole(ctx context.Context, projectID, key string) } func (q *Queries) SearchProjectRoles(ctx context.Context, queries *ProjectRoleSearchQueries) (projects *ProjectRoles, err error) { - query, scan := q.prepareProjectRolesQuery() + query, scan := prepareProjectRolesQuery() stmt, args, err := queries.toQuery(query).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-3N9ff", "Errors.Query.InvalidRequest") @@ -123,7 +123,7 @@ func (q *Queries) SearchGrantedProjectRoles(ctx context.Context, grantID, grante if err != nil { return nil, err } - query, scan := q.prepareProjectRolesQuery() + query, scan := prepareProjectRolesQuery() stmt, args, err := queries.toQuery(query).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-3N9ff", "Errors.Query.InvalidRequest") @@ -237,7 +237,7 @@ func prepareProjectRoleQuery() (sq.SelectBuilder, func(*sql.Row) (*ProjectRole, } } -func (q *Queries) prepareProjectRolesQuery() (sq.SelectBuilder, func(*sql.Rows) (*ProjectRoles, error)) { +func prepareProjectRolesQuery() (sq.SelectBuilder, func(*sql.Rows) (*ProjectRoles, error)) { return sq.Select( ProjectRoleColumnProjectID.identifier(), ProjectRoleColumnCreationDate.identifier(), diff --git a/internal/query/project_role_test.go b/internal/query/project_role_test.go new file mode 100644 index 0000000000..18ee4ae152 --- /dev/null +++ b/internal/query/project_role_test.go @@ -0,0 +1,312 @@ +package query + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "regexp" + "testing" + + errs "github.com/caos/zitadel/internal/errors" +) + +func Test_ProjectRolePrepares(t *testing.T) { + type want struct { + sqlExpectations sqlExpectation + err checkErr + } + tests := []struct { + name string + prepare interface{} + want want + object interface{} + }{ + { + name: "prepareProjectRolesQuery no result", + prepare: prepareProjectRolesQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(`SELECT zitadel.projections.project_roles.project_id,`+ + ` zitadel.projections.project_roles.creation_date,`+ + ` zitadel.projections.project_roles.change_date,`+ + ` zitadel.projections.project_roles.resource_owner,`+ + ` zitadel.projections.project_roles.sequence,`+ + ` zitadel.projections.project_roles.role_key,`+ + ` zitadel.projections.project_roles.display_name,`+ + ` zitadel.projections.project_roles.group_name,`+ + ` COUNT(*) OVER ()`+ + ` FROM zitadel.projections.project_roles`), + nil, + nil, + ), + }, + object: &ProjectRoles{ProjectRoles: []*ProjectRole{}}, + }, + { + name: "prepareProjectRolesQuery one result", + prepare: prepareProjectRolesQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(`SELECT zitadel.projections.project_roles.project_id,`+ + ` zitadel.projections.project_roles.creation_date,`+ + ` zitadel.projections.project_roles.change_date,`+ + ` zitadel.projections.project_roles.resource_owner,`+ + ` zitadel.projections.project_roles.sequence,`+ + ` zitadel.projections.project_roles.role_key,`+ + ` zitadel.projections.project_roles.display_name,`+ + ` zitadel.projections.project_roles.group_name,`+ + ` COUNT(*) OVER ()`+ + ` FROM zitadel.projections.project_roles`), + []string{ + "project_id", + "creation_date", + "change_date", + "resource_owner", + "sequence", + "role_key", + "display_name", + "group_name", + "count", + }, + [][]driver.Value{ + { + "project-id", + testNow, + testNow, + "ro", + uint64(20211111), + "role-key", + "role-display-name", + "role-group", + }, + }, + ), + }, + object: &ProjectRoles{ + SearchResponse: SearchResponse{ + Count: 1, + }, + ProjectRoles: []*ProjectRole{ + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + Key: "role-key", + DisplayName: "role-display-name", + Group: "role-group", + }, + }, + }, + }, + { + name: "prepareProjectRolesQuery multiple result", + prepare: prepareProjectRolesQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(`SELECT zitadel.projections.project_roles.project_id,`+ + ` zitadel.projections.project_roles.creation_date,`+ + ` zitadel.projections.project_roles.change_date,`+ + ` zitadel.projections.project_roles.resource_owner,`+ + ` zitadel.projections.project_roles.sequence,`+ + ` zitadel.projections.project_roles.role_key,`+ + ` zitadel.projections.project_roles.display_name,`+ + ` zitadel.projections.project_roles.group_name,`+ + ` COUNT(*) OVER ()`+ + ` FROM zitadel.projections.project_roles`), + []string{ + "project_id", + "creation_date", + "change_date", + "resource_owner", + "sequence", + "role_key", + "display_name", + "group_name", + "count", + }, + [][]driver.Value{ + { + "project-id", + testNow, + testNow, + "ro", + uint64(20211111), + "role-key-1", + "role-display-name-1", + "role-group", + }, + { + "project-id", + testNow, + testNow, + "ro", + uint64(20211111), + "role-key-2", + "role-display-name-2", + "role-group", + }, + }, + ), + }, + object: &ProjectRoles{ + SearchResponse: SearchResponse{ + Count: 2, + }, + ProjectRoles: []*ProjectRole{ + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + Key: "role-key-1", + DisplayName: "role-display-name-1", + Group: "role-group", + }, + { + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + Key: "role-key-2", + DisplayName: "role-display-name-2", + Group: "role-group", + }, + }, + }, + }, + { + name: "prepareProjectRolesQuery sql err", + prepare: prepareProjectRolesQuery, + want: want{ + sqlExpectations: mockQueryErr( + regexp.QuoteMeta(`SELECT zitadel.projections.project_roles.project_id,`+ + ` zitadel.projections.project_roles.creation_date,`+ + ` zitadel.projections.project_roles.change_date,`+ + ` zitadel.projections.project_roles.resource_owner,`+ + ` zitadel.projections.project_roles.sequence,`+ + ` zitadel.projections.project_roles.role_key,`+ + ` zitadel.projections.project_roles.display_name,`+ + ` zitadel.projections.project_roles.group_name,`+ + ` COUNT(*) OVER ()`+ + ` FROM zitadel.projections.project_roles`), + sql.ErrConnDone, + ), + err: func(err error) (error, bool) { + if !errors.Is(err, sql.ErrConnDone) { + return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false + } + return nil, true + }, + }, + object: nil, + }, + { + name: "prepareProjectRoleQuery no result", + prepare: prepareProjectRoleQuery, + want: want{ + sqlExpectations: mockQueries( + regexp.QuoteMeta(`SELECT zitadel.projections.project_roles.project_id,`+ + ` zitadel.projections.project_roles.creation_date,`+ + ` zitadel.projections.project_roles.change_date,`+ + ` zitadel.projections.project_roles.resource_owner,`+ + ` zitadel.projections.project_roles.sequence,`+ + ` zitadel.projections.project_roles.role_key,`+ + ` zitadel.projections.project_roles.display_name,`+ + ` zitadel.projections.project_roles.group_name`+ + ` FROM zitadel.projections.project_roles`), + nil, + nil, + ), + err: func(err error) (error, bool) { + if !errs.IsNotFound(err) { + return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false + } + return nil, true + }, + }, + object: (*ProjectRole)(nil), + }, + { + name: "prepareProjectRoleQuery found", + prepare: prepareProjectRoleQuery, + want: want{ + sqlExpectations: mockQuery( + regexp.QuoteMeta(`SELECT zitadel.projections.project_roles.project_id,`+ + ` zitadel.projections.project_roles.creation_date,`+ + ` zitadel.projections.project_roles.change_date,`+ + ` zitadel.projections.project_roles.resource_owner,`+ + ` zitadel.projections.project_roles.sequence,`+ + ` zitadel.projections.project_roles.role_key,`+ + ` zitadel.projections.project_roles.display_name,`+ + ` zitadel.projections.project_roles.group_name`+ + ` FROM zitadel.projections.project_roles`), + []string{ + "project_id", + "creation_date", + "change_date", + "resource_owner", + "sequence", + "role_key", + "display_name", + "group_name", + }, + []driver.Value{ + "project-id", + testNow, + testNow, + "ro", + uint64(20211111), + "role-key", + "role-display-name", + "role-group", + }, + ), + }, + object: &ProjectRole{ + ProjectID: "project-id", + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211111, + Key: "role-key", + DisplayName: "role-display-name", + Group: "role-group", + }, + }, + { + name: "prepareProjectRoleQuery sql err", + prepare: prepareProjectRoleQuery, + want: want{ + sqlExpectations: mockQueryErr( + regexp.QuoteMeta(`SELECT zitadel.projections.project_roles.project_id,`+ + ` zitadel.projections.project_roles.creation_date,`+ + ` zitadel.projections.project_roles.change_date,`+ + ` zitadel.projections.project_roles.resource_owner,`+ + ` zitadel.projections.project_roles.sequence,`+ + ` zitadel.projections.project_roles.role_key,`+ + ` zitadel.projections.project_roles.display_name,`+ + ` zitadel.projections.project_roles.group_name`+ + ` FROM zitadel.projections.project_roles`), + sql.ErrConnDone, + ), + err: func(err error) (error, bool) { + if !errors.Is(err, sql.ErrConnDone) { + return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false + } + return nil, true + }, + }, + object: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err) + }) + } +}