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  }