github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/teams/rename_test.go (about)

     1  package teams
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/keybase/client/go/kbtest"
     8  	"github.com/keybase/client/go/protocol/keybase1"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestRenameSimple(t *testing.T) {
    13  	tc := SetupTest(t, "team", 1)
    14  	defer tc.Cleanup()
    15  
    16  	u, err := kbtest.CreateAndSignupFakeUser("t", tc.G)
    17  	require.NoError(t, err)
    18  
    19  	parentTeamName, err := keybase1.TeamNameFromString(u.Username + "T")
    20  	require.NoError(t, err)
    21  	_, err = CreateRootTeam(context.TODO(), tc.G, parentTeamName.String(), keybase1.TeamSettings{})
    22  	require.NoError(t, err)
    23  
    24  	subteamBasename := "bb1"
    25  	subteamID, err := CreateSubteam(context.TODO(), tc.G, subteamBasename, parentTeamName, keybase1.TeamRole_NONE /* addSelfAs */)
    26  	require.NoError(t, err)
    27  	subteamName, err := parentTeamName.Append(subteamBasename)
    28  	require.NoError(t, err)
    29  	desiredName, err := parentTeamName.Append("bb2")
    30  	require.NoError(t, err)
    31  
    32  	err = RenameSubteam(context.TODO(), tc.G, subteamName, desiredName)
    33  	require.NoError(t, err)
    34  
    35  	t.Logf("load the renamed team")
    36  	subteam, err := Load(context.TODO(), tc.G, keybase1.LoadTeamArg{
    37  		ID:          *subteamID,
    38  		ForceRepoll: true,
    39  	})
    40  	require.NoError(t, err)
    41  	require.Equal(t, parentTeamName.String()+".bb2", subteam.Name().String(), "new name")
    42  
    43  	t.Logf("load the parent")
    44  	parent, err := Load(context.TODO(), tc.G, keybase1.LoadTeamArg{
    45  		Name:        parentTeamName.String(),
    46  		NeedAdmin:   true,
    47  		ForceRepoll: true,
    48  	})
    49  	require.NoError(t, err)
    50  	subteamList := parent.chain().ListSubteams()
    51  	require.Len(t, subteamList, 1, "has 1 subteam")
    52  	require.Equal(t, subteamList[0].Name.String(), parentTeamName.String()+".bb2")
    53  	require.Equal(t, subteamList[0].Id.String(), subteamID.String())
    54  	require.Len(t, parent.chain().inner.SubteamLog, 1, "subteam log has 1 series")
    55  	require.Len(t, parent.chain().inner.SubteamLog[*subteamID], 2, "subteam log has 2 entries")
    56  }
    57  
    58  // This was a bug that once caused the loader to get stuck.
    59  // - Create team A
    60  // - Create team A.B1
    61  // - Create team A.B1.C <new_subteam>
    62  // - Rename A.B1 -> A.B2 (implicitly renaming A.B1.C -> A.B2.C)
    63  // - Someone else (U1) loads A.B2 with <new_subteam> stubbed
    64  // - Add U1 as an admin of A.B2 or as a member of A.B2's subtree.
    65  // - U1 loads and inflates <new_subteam>.
    66  // The last step failed because the new_subteam link says A.B1.C
    67  // but that doesn't look like a valid subteam name of A.B2.
    68  func TestRenameInflateSubteamAfterRenameParent(t *testing.T) {
    69  	fus, tcs, cleanup := setupNTests(t, 2)
    70  	defer cleanup()
    71  
    72  	t.Logf("U0 creates A")
    73  	parentName, _ := createTeam2(*tcs[0])
    74  
    75  	subteamName1 := createTeamName(t, parentName.String(), "bb1")
    76  	subteamName2 := createTeamName(t, parentName.String(), "bb2")
    77  	subsubteamName2 := createTeamName(t, parentName.String(), "bb2", "cc")
    78  
    79  	t.Logf("U0 creates A.B1")
    80  	subteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "bb1", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
    81  	require.NoError(t, err)
    82  
    83  	t.Logf("U0 creates A.B1.C")
    84  	subsubteamID, err := CreateSubteam(context.TODO(), tcs[0].G, "cc", subteamName1, keybase1.TeamRole_NONE /* addSelfAs */)
    85  	require.NoError(t, err)
    86  
    87  	t.Logf("U0 adds U1 to A.B1 as a writer")
    88  	_, err = AddMember(context.TODO(), tcs[0].G, subteamName1.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
    89  	require.NoError(t, err)
    90  
    91  	t.Logf("U0 renames A.B1 -> A.B2")
    92  	err = RenameSubteam(context.TODO(), tcs[0].G, subteamName1, subteamName2)
    93  	require.NoError(t, err)
    94  
    95  	t.Logf("U1 loads A.B1 (will have stubbed link and new name)")
    96  	_, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
    97  		ID:          *subteamID,
    98  		ForceRepoll: true,
    99  	})
   100  	require.NoError(t, err, "load subsubteam")
   101  
   102  	t.Logf("U0 adds U1 to A.B2.C as a writer")
   103  	_, err = AddMember(context.TODO(), tcs[0].G, subsubteamName2.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   104  	require.NoError(t, err)
   105  
   106  	t.Logf("U1 loads A.B2.C which will cause it to inflate the new_subteam link in A.B2")
   107  	_, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   108  		ID:          *subsubteamID,
   109  		ForceRepoll: true,
   110  	})
   111  	require.NoError(t, err, "load subsubteam")
   112  }
   113  
   114  // This was a bug that once caused the loader to get stuck.
   115  // A situation where it looks like there is a subteam name
   116  // collision when there is not. Because of a stubbed link.
   117  // U1 is a member of R
   118  // U1 gets added to R.B and caches that subteam log entry
   119  // U1 gets removed from R.B
   120  // A.B gets renames to R.C
   121  // A new R.B gets created (different subteam ID)
   122  // U1 gets added to R.B and loads.
   123  //
   124  //	They see a name conflict and fail to load, but it's not real.
   125  func TestRenameIntoMovedSubteam(t *testing.T) {
   126  	fus, tcs, cleanup := setupNTests(t, 2)
   127  	defer cleanup()
   128  
   129  	t.Logf("U0 creates R")
   130  	parentName, _ := createTeam2(*tcs[0])
   131  
   132  	t.Logf("U0 adds U1 to R as a WRITER")
   133  	_, err := AddMember(context.TODO(), tcs[0].G, parentName.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   134  	require.NoError(t, err)
   135  
   136  	subteamNameB := createTeamName(t, parentName.String(), "bbb")
   137  	subteamNameC := createTeamName(t, parentName.String(), "ccc")
   138  
   139  	t.Logf("U0 creates R.B (subteam 1)")
   140  	subteamID1, err := CreateSubteam(context.TODO(), tcs[0].G, "bbb", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   141  	require.NoError(t, err)
   142  	_ = subteamID1
   143  
   144  	t.Logf("U0 adds U1 to R.B (1) as a WRITER")
   145  	_, err = AddMember(context.TODO(), tcs[0].G, subteamNameB.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   146  	require.NoError(t, err)
   147  
   148  	t.Logf("U1 loads R")
   149  	_, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   150  		ID:          parentName.ToPrivateTeamID(),
   151  		ForceRepoll: true,
   152  	})
   153  	require.NoError(t, err)
   154  
   155  	t.Logf("U0 removes U1 from R.B (1)")
   156  	err = RemoveMember(context.TODO(), tcs[0].G, subteamNameB.String(), fus[1].Username)
   157  	require.NoError(t, err)
   158  
   159  	t.Logf("U0 renames R.B (1) to R.C")
   160  	err = RenameSubteam(context.TODO(), tcs[0].G, subteamNameB, subteamNameC)
   161  	require.NoError(t, err)
   162  
   163  	t.Logf("U0 creates R.B (subteam 2) which is the SECOND R.B to be created")
   164  	subteamID2, err := CreateSubteam(context.TODO(), tcs[0].G, "bbb", parentName, keybase1.TeamRole_NONE /* addSelfAs */)
   165  	require.NoError(t, err)
   166  	_ = subteamID2
   167  
   168  	t.Logf("U0 adds U1 to R.B (2) as a WRITER")
   169  	_, err = AddMember(context.TODO(), tcs[0].G, subteamNameB.String(), fus[1].Username, keybase1.TeamRole_WRITER, nil)
   170  	require.NoError(t, err)
   171  
   172  	t.Logf("U1 loads R")
   173  	_, _, err = tcs[1].G.GetTeamLoader().Load(context.TODO(), keybase1.LoadTeamArg{
   174  		ID:          parentName.ToPrivateTeamID(),
   175  		ForceRepoll: true,
   176  	})
   177  	require.NoError(t, err)
   178  
   179  	// TODO check the subteam list
   180  }
   181  
   182  func testHiddenRotateRename(t *testing.T, rotateParent bool, rotateChild bool) {
   183  	tc := SetupTest(t, "team", 1)
   184  	defer tc.Cleanup()
   185  
   186  	u, err := kbtest.CreateAndSignupFakeUser("t", tc.G)
   187  	require.NoError(t, err)
   188  
   189  	parentTeamName, err := keybase1.TeamNameFromString(u.Username + "T")
   190  	require.NoError(t, err)
   191  	parentTeamID, err := CreateRootTeam(context.TODO(), tc.G, parentTeamName.String(), keybase1.TeamSettings{})
   192  	require.NoError(t, err)
   193  
   194  	subteamBasename := "bb1"
   195  	subteamID, err := CreateSubteam(context.TODO(), tc.G, subteamBasename, parentTeamName, keybase1.TeamRole_NONE /* addSelfAs */)
   196  	require.NoError(t, err)
   197  	subteamName, err := parentTeamName.Append(subteamBasename)
   198  	require.NoError(t, err)
   199  	desiredName, err := parentTeamName.Append("bb2")
   200  	require.NoError(t, err)
   201  
   202  	if rotateParent {
   203  		parentTeam, err := GetForTestByID(context.TODO(), tc.G, *parentTeamID)
   204  		require.NoError(t, err)
   205  		err = parentTeam.Rotate(context.TODO(), keybase1.RotationType_HIDDEN)
   206  		require.NoError(t, err)
   207  	}
   208  
   209  	if rotateChild {
   210  		subteam, err := GetForTestByID(context.TODO(), tc.G, *subteamID)
   211  		require.NoError(t, err)
   212  		err = subteam.Rotate(context.TODO(), keybase1.RotationType_HIDDEN)
   213  		require.NoError(t, err)
   214  	}
   215  
   216  	err = RenameSubteam(context.TODO(), tc.G, subteamName, desiredName)
   217  	require.NoError(t, err)
   218  }
   219  
   220  func TestHiddenRotateRenameChild(t *testing.T) {
   221  	testHiddenRotateRename(t, false, true)
   222  }
   223  func TestHiddenRotateRenameParent(t *testing.T) {
   224  	testHiddenRotateRename(t, true, false)
   225  }
   226  func TestHiddenRotateRenameParentAndChild(t *testing.T) {
   227  	testHiddenRotateRename(t, true, true)
   228  }