|
1 | 1 | package idpsync_test
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | +"database/sql" |
4 | 5 | "testing"
|
5 | 6 |
|
6 | 7 | "github.com/golang-jwt/jwt/v4"
|
7 | 8 | "github.com/google/uuid"
|
8 | 9 | "github.com/stretchr/testify/require"
|
9 | 10 |
|
10 | 11 | "cdr.dev/slog/sloggers/slogtest"
|
| 12 | +"github.com/coder/coder/v2/coderd/database" |
| 13 | +"github.com/coder/coder/v2/coderd/database/db2sdk" |
| 14 | +"github.com/coder/coder/v2/coderd/database/dbfake" |
| 15 | +"github.com/coder/coder/v2/coderd/database/dbgen" |
| 16 | +"github.com/coder/coder/v2/coderd/database/dbtestutil" |
11 | 17 | "github.com/coder/coder/v2/coderd/idpsync"
|
12 | 18 | "github.com/coder/coder/v2/coderd/runtimeconfig"
|
13 | 19 | "github.com/coder/coder/v2/testutil"
|
@@ -38,3 +44,108 @@ func TestParseOrganizationClaims(t *testing.T) {
|
38 | 44 | require.False(t,params.SyncEntitled)
|
39 | 45 | })
|
40 | 46 | }
|
| 47 | + |
| 48 | +funcTestSyncOrganizations(t*testing.T) { |
| 49 | +t.Parallel() |
| 50 | + |
| 51 | +// This test creates some deleted organizations and checks the behavior is |
| 52 | +// correct. |
| 53 | +t.Run("SyncUserToDeletedOrg",func(t*testing.T) { |
| 54 | +t.Parallel() |
| 55 | + |
| 56 | +ctx:=testutil.Context(t,testutil.WaitMedium) |
| 57 | +db,_:=dbtestutil.NewDB(t) |
| 58 | +user:=dbgen.User(t,db, database.User{}) |
| 59 | + |
| 60 | +// Create orgs for: |
| 61 | +// - stays = User is a member, and stays |
| 62 | +// - leaves = User is a member, and leaves |
| 63 | +// - joins = User is not a member, and joins |
| 64 | +// For deleted orgs, the user **should not** be a member of afterwards. |
| 65 | +// - deletedStays = User is a member of deleted org, and wants to stay |
| 66 | +// - deletedLeaves = User is a member of deleted org, and wants to leave |
| 67 | +// - deletedJoins = User is not a member of deleted org, and wants to join |
| 68 | +stays:=dbfake.Organization(t,db).Members(user).Do() |
| 69 | +leaves:=dbfake.Organization(t,db).Members(user).Do() |
| 70 | +joins:=dbfake.Organization(t,db).Do() |
| 71 | + |
| 72 | +deletedStays:=dbfake.Organization(t,db).Members(user).Deleted(true).Do() |
| 73 | +deletedLeaves:=dbfake.Organization(t,db).Members(user).Deleted(true).Do() |
| 74 | +deletedJoins:=dbfake.Organization(t,db).Deleted(true).Do() |
| 75 | + |
| 76 | +// Now sync the user to the deleted organization |
| 77 | +s:=idpsync.NewAGPLSync( |
| 78 | +slogtest.Make(t,&slogtest.Options{}), |
| 79 | +runtimeconfig.NewManager(), |
| 80 | +idpsync.DeploymentSyncSettings{ |
| 81 | +OrganizationField:"orgs", |
| 82 | +OrganizationMapping:map[string][]uuid.UUID{ |
| 83 | +"stay": {stays.Org.ID,deletedStays.Org.ID}, |
| 84 | +"leave": {leaves.Org.ID,deletedLeaves.Org.ID}, |
| 85 | +"join": {joins.Org.ID,deletedJoins.Org.ID}, |
| 86 | +}, |
| 87 | +OrganizationAssignDefault:false, |
| 88 | +}, |
| 89 | +) |
| 90 | + |
| 91 | +err:=s.SyncOrganizations(ctx,db,user, idpsync.OrganizationParams{ |
| 92 | +SyncEntitled:true, |
| 93 | +MergedClaims:map[string]interface{}{ |
| 94 | +"orgs": []string{"stay","join"}, |
| 95 | +}, |
| 96 | +}) |
| 97 | +require.NoError(t,err) |
| 98 | + |
| 99 | +orgs,err:=db.GetOrganizationsByUserID(ctx, database.GetOrganizationsByUserIDParams{ |
| 100 | +UserID:user.ID, |
| 101 | +Deleted: sql.NullBool{}, |
| 102 | +}) |
| 103 | +require.NoError(t,err) |
| 104 | +require.Len(t,orgs,2) |
| 105 | + |
| 106 | +// Verify the user only exists in 2 orgs. The one they stayed, and the one they |
| 107 | +// joined. |
| 108 | +inIDs:=db2sdk.List(orgs,func(org database.Organization) uuid.UUID { |
| 109 | +returnorg.ID |
| 110 | +}) |
| 111 | +require.ElementsMatch(t, []uuid.UUID{stays.Org.ID,joins.Org.ID},inIDs) |
| 112 | +}) |
| 113 | + |
| 114 | +t.Run("UserToZeroOrgs",func(t*testing.T) { |
| 115 | +t.Parallel() |
| 116 | + |
| 117 | +ctx:=testutil.Context(t,testutil.WaitMedium) |
| 118 | +db,_:=dbtestutil.NewDB(t) |
| 119 | +user:=dbgen.User(t,db, database.User{}) |
| 120 | + |
| 121 | +deletedLeaves:=dbfake.Organization(t,db).Members(user).Deleted(true).Do() |
| 122 | + |
| 123 | +// Now sync the user to the deleted organization |
| 124 | +s:=idpsync.NewAGPLSync( |
| 125 | +slogtest.Make(t,&slogtest.Options{}), |
| 126 | +runtimeconfig.NewManager(), |
| 127 | +idpsync.DeploymentSyncSettings{ |
| 128 | +OrganizationField:"orgs", |
| 129 | +OrganizationMapping:map[string][]uuid.UUID{ |
| 130 | +"leave": {deletedLeaves.Org.ID}, |
| 131 | +}, |
| 132 | +OrganizationAssignDefault:false, |
| 133 | +}, |
| 134 | +) |
| 135 | + |
| 136 | +err:=s.SyncOrganizations(ctx,db,user, idpsync.OrganizationParams{ |
| 137 | +SyncEntitled:true, |
| 138 | +MergedClaims:map[string]interface{}{ |
| 139 | +"orgs": []string{}, |
| 140 | +}, |
| 141 | +}) |
| 142 | +require.NoError(t,err) |
| 143 | + |
| 144 | +orgs,err:=db.GetOrganizationsByUserID(ctx, database.GetOrganizationsByUserIDParams{ |
| 145 | +UserID:user.ID, |
| 146 | +Deleted: sql.NullBool{}, |
| 147 | +}) |
| 148 | +require.NoError(t,err) |
| 149 | +require.Len(t,orgs,0) |
| 150 | +}) |
| 151 | +} |