github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/delete_test.go (about) 1 package teams 2 3 import ( 4 "testing" 5 6 "golang.org/x/net/context" 7 8 "github.com/davecgh/go-spew/spew" 9 "github.com/keybase/client/go/libkb" 10 "github.com/keybase/client/go/protocol/keybase1" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func assertCanUserPerformTeamDelete(t *testing.T, g *libkb.GlobalContext, teamname string) { 15 teamOp, err := CanUserPerform(context.Background(), g, teamname) 16 require.NoError(t, err) 17 require.True(t, teamOp.DeleteTeam) 18 } 19 20 func TestDeleteRoot(t *testing.T) { 21 tc, u, teamname := memberSetup(t) 22 defer tc.Cleanup() 23 24 assertRole(tc, teamname, u.Username, keybase1.TeamRole_OWNER) 25 26 assertCanUserPerformTeamDelete(t, tc.G, teamname) 27 team, err := GetTeamByNameForTest(context.Background(), tc.G, teamname, false, false) 28 require.NoError(t, err, "error getting team before delete") 29 30 if err := Delete(context.Background(), tc.G, &teamsUI{}, team.ID); err != nil { 31 t.Fatal(err) 32 } 33 34 _, err = GetTeamByNameForTest(context.Background(), tc.G, teamname, false, false) 35 require.Error(t, err, "no error getting deleted team") 36 _, ok := err.(*TeamTombstonedError) 37 require.True(t, ok) // ensure server cannot temporarily pretend a team was deleted 38 } 39 40 func TestDeleteSubteamAdmin(t *testing.T) { 41 tc, owner, admin, _, root, sub := memberSetupSubteam(t) 42 defer tc.Cleanup() 43 44 assertRole(tc, root, owner.Username, keybase1.TeamRole_OWNER) 45 assertRole(tc, root, admin.Username, keybase1.TeamRole_ADMIN) 46 47 _, err := AddMember(context.TODO(), tc.G, sub, admin.Username, keybase1.TeamRole_ADMIN, nil) 48 if err != nil { 49 t.Fatal(err) 50 } 51 assertRole(tc, sub, owner.Username, keybase1.TeamRole_NONE) 52 assertRole(tc, sub, admin.Username, keybase1.TeamRole_ADMIN) 53 54 // switch to `admin` user 55 err = tc.Logout() 56 require.NoError(t, err) 57 if err := admin.Login(tc.G); err != nil { 58 t.Fatal(err) 59 } 60 61 assertCanUserPerformTeamDelete(t, tc.G, sub) 62 team, err := GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 63 require.NoError(t, err, "error getting team before delete") 64 65 if err := Delete(context.Background(), tc.G, &teamsUI{}, team.ID); err != nil { 66 t.Fatal(err) 67 } 68 69 _, err = GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 70 if err == nil { 71 t.Fatal("no error getting deleted team") 72 } 73 aerr, ok := err.(libkb.AppStatusError) 74 if !ok { 75 t.Fatalf("error type: %T (%s), expected libkb.AppStatusError", err, err) 76 } 77 if aerr.Code != int(keybase1.StatusCode_SCTeamReadError) { 78 t.Errorf("error status code: %d, expected %d (%s)", aerr.Code, keybase1.StatusCode_SCTeamReadError, aerr) 79 } 80 } 81 82 func TestDeleteSubteamImpliedAdmin(t *testing.T) { 83 tc, owner, admin, _, root, sub := memberSetupSubteam(t) 84 defer tc.Cleanup() 85 86 assertRole(tc, root, owner.Username, keybase1.TeamRole_OWNER) 87 assertRole(tc, root, admin.Username, keybase1.TeamRole_ADMIN) 88 assertRole(tc, sub, owner.Username, keybase1.TeamRole_NONE) 89 assertRole(tc, sub, admin.Username, keybase1.TeamRole_NONE) 90 91 // switch to `admin` user 92 err := tc.Logout() 93 require.NoError(t, err) 94 if err := admin.Login(tc.G); err != nil { 95 t.Fatal(err) 96 } 97 98 assertCanUserPerformTeamDelete(t, tc.G, sub) 99 team, err := GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 100 require.NoError(t, err, "error getting team before delete") 101 102 if err := Delete(context.Background(), tc.G, &teamsUI{}, team.ID); err != nil { 103 t.Fatal(err) 104 } 105 106 _, err = GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 107 if err == nil { 108 t.Fatal("no error getting deleted team") 109 } 110 aerr, ok := err.(libkb.AppStatusError) 111 if !ok { 112 t.Fatalf("error type: %T (%s), expected libkb.AppStatusError", err, err) 113 } 114 if aerr.Code != int(keybase1.StatusCode_SCTeamReadError) { 115 t.Errorf("error status code: %d, expected %d (%s)", aerr.Code, keybase1.StatusCode_SCTeamReadError, aerr) 116 } 117 } 118 119 func TestDeleteSubteamWithHiddenRotations(t *testing.T) { 120 tc, owner, admin, _, root, sub := memberSetupSubteam(t) 121 defer tc.Cleanup() 122 123 assertRole(tc, root, owner.Username, keybase1.TeamRole_OWNER) 124 assertRole(tc, root, admin.Username, keybase1.TeamRole_ADMIN) 125 assertRole(tc, sub, owner.Username, keybase1.TeamRole_NONE) 126 assertRole(tc, sub, admin.Username, keybase1.TeamRole_NONE) 127 128 // switch to `admin` user 129 err := tc.Logout() 130 require.NoError(t, err) 131 if err := admin.Login(tc.G); err != nil { 132 t.Fatal(err) 133 } 134 135 subTeam, err := GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 136 require.NoError(t, err) 137 138 err = subTeam.Rotate(context.TODO(), keybase1.RotationType_HIDDEN) 139 require.NoError(t, err) 140 141 rootTeam, err := GetTeamByNameForTest(context.Background(), tc.G, root, false, false) 142 require.NoError(t, err) 143 144 err = rootTeam.Rotate(context.TODO(), keybase1.RotationType_HIDDEN) 145 require.NoError(t, err) 146 147 assertCanUserPerformTeamDelete(t, tc.G, sub) 148 subTeam, err = GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 149 require.NoError(t, err, "error getting team before delete") 150 151 if err := Delete(context.Background(), tc.G, &teamsUI{}, subTeam.ID); err != nil { 152 t.Fatal(err) 153 } 154 155 _, err = GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 156 if err == nil { 157 t.Fatal("no error getting deleted team") 158 } 159 aerr, ok := err.(libkb.AppStatusError) 160 if !ok { 161 t.Fatalf("error type: %T (%s), expected libkb.AppStatusError", err, err) 162 } 163 if aerr.Code != int(keybase1.StatusCode_SCTeamReadError) { 164 t.Errorf("error status code: %d, expected %d (%s)", aerr.Code, keybase1.StatusCode_SCTeamReadError, aerr) 165 } 166 } 167 168 func TestRecreateSubteam(t *testing.T) { 169 tc, _, admin, _, _, sub := memberSetupSubteam(t) 170 defer tc.Cleanup() 171 172 // switch to `admin` user 173 err := tc.Logout() 174 require.NoError(t, err) 175 if err := admin.Login(tc.G); err != nil { 176 t.Fatal(err) 177 } 178 179 assertCanUserPerformTeamDelete(t, tc.G, sub) 180 team, err := GetTeamByNameForTest(context.Background(), tc.G, sub, false, false) 181 require.NoError(t, err, "error getting team before delete") 182 183 if err := Delete(context.Background(), tc.G, &teamsUI{}, team.ID); err != nil { 184 t.Fatal(err) 185 } 186 187 // create the subteam again 188 name, err := keybase1.TeamNameFromString(sub) 189 if err != nil { 190 t.Fatal(err) 191 } 192 parent, err := name.Parent() 193 if err != nil { 194 t.Fatal(err) 195 } 196 _, err = CreateSubteam(context.Background(), tc.G, string(name.LastPart()), parent, keybase1.TeamRole_NONE /* addSelfAs */) 197 if err != nil { 198 t.Fatal(err) 199 } 200 } 201 202 // U0 creates a subteam and deletes it 203 // U0 creates a subteam and deletes it again 204 // U1 loads the root team. 205 func TestDeleteTwoSubteams(t *testing.T) { 206 fus, tcs, cleanup := setupNTests(t, 2) 207 defer cleanup() 208 209 t.Logf("U0 creates A") 210 parentName, parentID := createTeam2(*tcs[0]) 211 212 subteamName1 := createTeamName(t, parentName.String(), "bbb") 213 subteamName2 := createTeamName(t, parentName.String(), "ccc") 214 215 t.Logf("U0 creates A.B") 216 _, err := CreateSubteam(context.TODO(), tcs[0].G, "bbb", parentName, keybase1.TeamRole_NONE /* addSelfAs */) 217 require.NoError(t, err) 218 219 t.Logf("U0 deletes A.B") 220 assertCanUserPerformTeamDelete(t, tcs[0].G, subteamName1.String()) 221 team, err := GetTeamByNameForTest(context.Background(), tcs[0].G, subteamName1.String(), false, false) 222 require.NoError(t, err, "error getting team before delete") 223 err = Delete(context.Background(), tcs[0].G, &teamsUI{}, team.ID) 224 require.NoError(t, err) 225 226 t.Logf("U0 creates A.C") 227 _, err = CreateSubteam(context.TODO(), tcs[0].G, "ccc", parentName, keybase1.TeamRole_NONE /* addSelfAs */) 228 require.NoError(t, err) 229 230 t.Logf("U0 deletes A.C") 231 assertCanUserPerformTeamDelete(t, tcs[0].G, subteamName2.String()) 232 team, err = GetTeamByNameForTest(context.Background(), tcs[0].G, subteamName2.String(), false, false) 233 require.NoError(t, err, "error getting team before delete") 234 err = Delete(context.Background(), tcs[0].G, &teamsUI{}, team.ID) 235 require.NoError(t, err) 236 237 t.Logf("U0 adds U1 to A") 238 _, err = AddMember(context.TODO(), tcs[0].G, parentName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil) 239 require.NoError(t, err) 240 241 t.Logf("U1 loads A") 242 team, err = Load(context.TODO(), tcs[1].G, keybase1.LoadTeamArg{ 243 ID: parentID, 244 }) 245 require.NoError(t, err, "load team") 246 t.Logf(spew.Sdump(team.chain().inner.SubteamLog)) 247 require.Len(t, team.chain().inner.SubteamLog, 0, "subteam log should be empty because all subteam links were stubbed for this user") 248 } 249 250 type teamsUI struct{} 251 252 func (t *teamsUI) ConfirmRootTeamDelete(context.Context, keybase1.ConfirmRootTeamDeleteArg) (bool, error) { 253 return true, nil 254 } 255 256 func (t *teamsUI) ConfirmSubteamDelete(context.Context, keybase1.ConfirmSubteamDeleteArg) (bool, error) { 257 return true, nil 258 } 259 260 func (t *teamsUI) ConfirmInviteLinkAccept(context.Context, keybase1.ConfirmInviteLinkAcceptArg) (bool, error) { 261 return true, nil 262 } 263 264 func TestDoubleTombstone(t *testing.T) { 265 tc, _, teamname := memberSetup(t) 266 defer tc.Cleanup() 267 name, err := keybase1.TeamNameFromString(teamname) 268 require.NoError(t, err) 269 270 id, err := ResolveNameToID(context.TODO(), tc.G, name) 271 require.NoError(t, err) 272 273 mctx := libkb.NewMetaContextForTest(tc) 274 275 err = TombstoneTeam(mctx, id) 276 require.NoError(t, err) 277 278 err = TombstoneTeam(mctx, id) 279 require.NoError(t, err, "errored on trying to tombstone a tombstoned team") 280 }