github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/subteam_rename_test.go (about) 1 package chat 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "testing" 8 "time" 9 10 "github.com/keybase/client/go/chat/types" 11 "github.com/keybase/client/go/chat/utils" 12 "github.com/keybase/client/go/protocol/chat1" 13 "github.com/keybase/client/go/protocol/keybase1" 14 "github.com/keybase/client/go/teams" 15 "github.com/stretchr/testify/require" 16 ) 17 18 func TestChatSubteamRename(t *testing.T) { 19 runWithMemberTypes(t, func(mt chat1.ConversationMembersType) { 20 switch mt { 21 case chat1.ConversationMembersType_TEAM: 22 default: 23 return 24 } 25 ctc := makeChatTestContext(t, "TestChatSubteamRename", 2) 26 defer ctc.cleanup() 27 users := ctc.users() 28 29 listener1 := newServerChatListener() 30 listener2 := newServerChatListener() 31 ctc.as(t, users[0]).h.G().NotifyRouter.AddListener(listener1) 32 ctc.as(t, users[1]).h.G().NotifyRouter.AddListener(listener2) 33 ctc.world.Tcs[users[0].Username].ChatG.Syncer.(*Syncer).isConnected = true 34 ctc.world.Tcs[users[1].Username].ChatG.Syncer.(*Syncer).isConnected = true 35 36 // Root team conv 37 teamConv := mustCreateConversationForTest(t, ctc, users[0], chat1.TopicType_CHAT, chat1.ConversationMembersType_TEAM, ctc.as(t, users[1]).user()) 38 // setup a sub team with user0, and user1, and a subsub team with only 39 // user1. both subteams have two channels. 40 parentTeamName, err := keybase1.TeamNameFromString(teamConv.TlfName) 41 require.NoError(t, err) 42 tc := ctc.world.Tcs[users[0].Username] 43 44 subteamBasename := "level1" 45 _, err = teams.CreateSubteam(context.TODO(), tc.G, subteamBasename, parentTeamName, keybase1.TeamRole_WRITER /* addSelfAs */) 46 require.NoError(t, err) 47 subteamName, err := parentTeamName.Append(subteamBasename) 48 require.NoError(t, err) 49 err = teams.SetRoleWriter(context.TODO(), tc.G, subteamName.String(), users[1].Username) 50 require.NoError(t, err) 51 ctc.teamCache[subteamName.String()] = subteamName.String() 52 53 subSubteamBasename := "level2" 54 _, err = teams.CreateSubteam(context.TODO(), tc.G, subSubteamBasename, subteamName, keybase1.TeamRole_WRITER /* addSelfAs */) 55 require.NoError(t, err) 56 subSubteamName, err := subteamName.Append(subSubteamBasename) 57 require.NoError(t, err) 58 ctc.teamCache[subSubteamName.String()] = subSubteamName.String() 59 60 versMap := make(map[chat1.ConvIDStr]chat1.ConversationVers) 61 var convs []chat1.ConversationInfoLocal 62 for _, name := range []string{subteamName.String(), subSubteamName.String()} { 63 for i := 0; i < 2; i++ { 64 t.Logf("creating conv %v, subteam: %vv", i, name) 65 var topicName *string 66 if i > 0 { 67 s := fmt.Sprintf("chan-%v", i) 68 topicName = &s 69 } 70 ctx := ctc.as(t, users[0]) 71 ncres, err := ctx.chatLocalHandler().NewConversationLocal(ctx.startCtx, 72 chat1.NewConversationLocalArg{ 73 TlfName: name, 74 TopicType: chat1.TopicType_CHAT, 75 TopicName: topicName, 76 TlfVisibility: keybase1.TLFVisibility_PRIVATE, 77 MembersType: chat1.ConversationMembersType_TEAM, 78 IdentifyBehavior: keybase1.TLFIdentifyBehavior_CHAT_CLI, 79 }) 80 require.NoError(t, err) 81 convs = append(convs, ncres.Conv.Info) 82 versMap[ncres.Conv.GetConvID().ConvIDStr()] = ncres.Conv.Info.Version 83 84 // Write a message so we have something that uses the old team name in the chat history. 85 _, err = ctc.as(t, users[0]).chatLocalHandler().PostLocal(context.TODO(), chat1.PostLocalArg{ 86 ConversationID: ncres.Conv.Info.Id, 87 Msg: chat1.MessagePlaintext{ 88 ClientHeader: chat1.MessageClientHeader{ 89 Conv: ncres.Conv.Info.Triple, 90 MessageType: chat1.MessageType_TEXT, 91 TlfName: ncres.Conv.Info.TlfName, 92 }, 93 MessageBody: chat1.NewMessageBodyWithText(chat1.MessageText{ 94 Body: "Hello", 95 }), 96 }, 97 }) 98 require.NoError(t, err) 99 } 100 } 101 102 // subteam convs 103 subConv1 := convs[0] // u1, u2 104 subConv2 := convs[1] // u1 105 // subSubteam convs 106 subSubConv1 := convs[2] // u1 107 subSubConv2 := convs[3] // u1 108 109 // Rename the subteam 110 newSubteamName, err := parentTeamName.Append("bb2") 111 require.NoError(t, err) 112 err = teams.RenameSubteam(context.TODO(), tc.G, subteamName, newSubteamName) 113 require.NoError(t, err) 114 newSubSubteamName, err := newSubteamName.Append(subSubteamBasename) 115 require.NoError(t, err) 116 117 u1ExpectedUpdates := []chat1.ConversationID{ 118 subConv1.Id, 119 subConv2.Id, 120 subSubConv1.Id, 121 subSubConv2.Id, 122 } 123 sort.Sort(utils.ByConvID(u1ExpectedUpdates)) 124 125 u1Updates := consumeSubteamRename(t, listener1) 126 sort.Sort(utils.ByConvID(u1Updates)) 127 require.Equal(t, u1ExpectedUpdates, u1Updates) 128 129 select { 130 case <-listener1.subteamRename: 131 require.Fail(t, "unexpected update") 132 case <-time.After(2 * time.Second): 133 } 134 135 u2ExpectedUpdates := []chat1.ConversationID{ 136 subConv1.Id, 137 } 138 139 u2Updates := consumeSubteamRename(t, listener2) 140 require.Equal(t, u2ExpectedUpdates, u2Updates) 141 142 select { 143 case <-listener2.subteamRename: 144 require.Fail(t, "unexpected update") 145 case <-time.After(2 * time.Second): 146 } 147 ib, _, err := tc.ChatG.InboxSource.Read(context.TODO(), users[0].User.GetUID().ToBytes(), 148 types.ConversationLocalizerBlocking, types.InboxSourceDataSourceAll, nil, 149 &chat1.GetInboxLocalQuery{ 150 ConvIDs: u1ExpectedUpdates, 151 }) 152 require.NoError(t, err) 153 require.True(t, len(ib.Convs) >= len(u1ExpectedUpdates)) 154 155 numFound := 0 156 for _, conv := range ib.Convs { 157 convID := conv.GetConvID() 158 if convID.Eq(subConv1.Id) || convID.Eq(subConv2.Id) { 159 require.Equal(t, newSubteamName.String(), conv.Info.TlfName) 160 numFound++ 161 } else if convID.Eq(subSubConv1.Id) || convID.Eq(subSubConv2.Id) { 162 require.Equal(t, newSubSubteamName.String(), conv.Info.TlfName) 163 numFound++ 164 } 165 require.NotEqual(t, versMap[conv.GetConvID().ConvIDStr()], conv.Info.Version) 166 167 // Make sure we can send to each conversation 168 _, err = ctc.as(t, users[0]).chatLocalHandler().PostLocal(context.TODO(), chat1.PostLocalArg{ 169 ConversationID: convID, 170 Msg: chat1.MessagePlaintext{ 171 ClientHeader: chat1.MessageClientHeader{ 172 Conv: conv.Info.Triple, 173 MessageType: chat1.MessageType_TEXT, 174 TlfName: conv.Info.TlfName, 175 }, 176 MessageBody: chat1.NewMessageBodyWithText(chat1.MessageText{ 177 Body: "Hello", 178 }), 179 }, 180 }) 181 require.NoError(t, err) 182 // Make sure user1 (user0 did all the sends) can decrypt everything 183 // in conversation. 184 tv, err := tc.Context().ConvSource.Pull(context.TODO(), convID, users[1].GetUID().ToBytes(), 185 chat1.GetThreadReason_GENERAL, nil, nil, nil) 186 require.NoError(t, err) 187 for _, msg := range tv.Messages { 188 if msg.IsJourneycard() { 189 continue 190 } 191 require.True(t, msg.IsValid()) 192 } 193 } 194 require.Equal(t, len(u1ExpectedUpdates), numFound) 195 }) 196 }