Skip to content

Commit 376bda3

Browse files
authored
Fix state update after channel.truncated event with a past date (#130)
* Fix state update after `channel.truncated` event with a past date * Add waiting for new message.received event when truncating in a unit test + add max waiting of 60s for a condition
1 parent 04a6508 commit 376bda3

6 files changed

Lines changed: 54 additions & 30 deletions

File tree

Assets/Plugins/StreamChat/Core/InternalDTO/Requests/MessageRequestInternalDTO.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal partial class MessageRequestInternalDTO
2323
/// Array of message attachments
2424
/// </summary>
2525
[Newtonsoft.Json.JsonProperty("attachments", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
26-
public System.Collections.Generic.List<AttachmentRequestInternalDTO> Attachments { get; set; } = new System.Collections.Generic.List<AttachmentRequestInternalDTO>();
26+
public System.Collections.Generic.List<AttachmentRequestInternalDTO> Attachments { get; set; }
2727

2828
/// <summary>
2929
/// Channel unique identifier in &lt;type&gt;:&lt;id&gt; format

Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -561,10 +561,6 @@ public async Task TruncateAsync(DateTimeOffset? truncatedAt = default, string sy
561561
TruncatedAt = truncatedAt
562562
});
563563
Cache.TryCreateOrUpdate(response.Channel);
564-
565-
//StreamTodo: this should not be needed but the truncate response doesn't contain messages nor any events are sent
566-
//so we can only query the channel to get the messages
567-
await Client.GetOrCreateChannelWithIdAsync(Type, Id);
568564
}
569565

570566
//StreamTodo: write test and check Client.WatchedChannels
@@ -721,13 +717,13 @@ internal void HandleChannelUpdatedEvent(ChannelUpdatedEventInternalDTO eventDto)
721717
internal void HandleChannelTruncatedEvent(ChannelTruncatedEventInternalDTO eventDto)
722718
{
723719
AssertCid(eventDto.Cid);
724-
InternalTruncateMessages(eventDto.CreatedAt, eventDto.Message);
720+
InternalTruncateMessages(eventDto.Channel.TruncatedAt, eventDto.Message);
725721
}
726722

727723
internal void HandleChannelTruncatedEvent(NotificationChannelTruncatedEventInternalDTO eventDto)
728724
{
729725
AssertCid(eventDto.Cid);
730-
InternalTruncateMessages(eventDto.CreatedAt);
726+
InternalTruncateMessages(eventDto.Channel.TruncatedAt);
731727
}
732728

733729
internal void InternalAddMember(StreamChannelMember member)

Assets/Plugins/StreamChat/Tests/StatefulClient/BaseStateIntegrationTests.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System;
33
using System.Collections;
44
using System.Collections.Generic;
5+
using System.Diagnostics;
56
using System.Linq;
67
using System.Threading.Tasks;
78
using NUnit.Framework;
@@ -10,7 +11,7 @@
1011
using StreamChat.Core.Requests;
1112
using StreamChat.Core.StatefulModels;
1213
using StreamChat.Libs.Auth;
13-
using UnityEngine;
14+
using Debug = UnityEngine.Debug;
1415

1516
namespace StreamChat.Tests.StatefulClient
1617
{
@@ -94,29 +95,47 @@ protected Task<IStreamChatClient> GetConnectedOtherClient()
9495
/// <summary>
9596
/// Use this if state update depends on receiving WS event that might come after the REST call was completed
9697
/// </summary>
97-
protected static async Task WaitWhileConditionTrueAsync(Func<bool> condition, int maxIterations = 500)
98+
protected static async Task WaitWhileTrueAsync(Func<bool> condition, int maxIterations = 500)
9899
{
100+
var sw = new Stopwatch();
101+
sw.Start();
102+
99103
for (int i = 0; i < maxIterations; i++)
100104
{
101105
if (!condition())
102106
{
103107
return;
104108
}
105109

106-
await Task.Delay(2);
110+
if (sw.Elapsed.Seconds > 60)
111+
{
112+
return;
113+
}
114+
115+
var delay = (int)Math.Max(1, Math.Min(400, Math.Pow(2, i)));
116+
await Task.Delay(delay);
107117
}
108118
}
109119

110-
protected static async Task WaitWhileConditionFalseAsync(Func<bool> condition, int maxIterations = 500)
120+
protected static async Task WaitWhileFalseAsync(Func<bool> condition, int maxIterations = 500)
111121
{
122+
var sw = new Stopwatch();
123+
sw.Start();
124+
112125
for (int i = 0; i < maxIterations; i++)
113126
{
114127
if (condition())
115128
{
116129
return;
117130
}
131+
132+
if (sw.Elapsed.Seconds > 60)
133+
{
134+
return;
135+
}
118136

119-
await Task.Delay(2);
137+
var delay = (int)Math.Max(1, Math.Min(400, Math.Pow(2, i)));
138+
await Task.Delay(delay);
120139
}
121140
}
122141

Assets/Plugins/StreamChat/Tests/StatefulClient/ChannelMembersTests.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ private async Task When_add_user_by_reference_to_channel_expect_user_included_in
3838

3939
await channel.AddMembersAsync(hideHistory: default, optionalMessage: default, otherUser);
4040

41-
await WaitWhileConditionTrueAsync(() => channel.Members.All(m => m.User != otherUser));
41+
await WaitWhileTrueAsync(() => channel.Members.All(m => m.User != otherUser));
4242
Assert.NotNull(channel.Members.FirstOrDefault(member => member.User == otherUser));
4343
}
4444

@@ -62,7 +62,7 @@ private async Task When_add_user_by_id_to_channel_expect_user_included_in_member
6262

6363
await channel.AddMembersAsync(hideHistory: default, optionalMessage: default, otherUser.Id);
6464

65-
await WaitWhileConditionTrueAsync(() => channel.Members.All(m => m.User != otherUser));
65+
await WaitWhileTrueAsync(() => channel.Members.All(m => m.User != otherUser));
6666
Assert.NotNull(channel.Members.FirstOrDefault(member => member.User == otherUser));
6767
}
6868

@@ -97,7 +97,7 @@ private async Task When_add_user_to_channel_with_hide_history_and_message_expect
9797
Text = memberAddedMsg
9898
}, otherUser.Id);
9999

100-
await WaitWhileConditionTrueAsync(() => channel.Members.All(m => m.User != otherUser));
100+
await WaitWhileTrueAsync(() => channel.Members.All(m => m.User != otherUser));
101101
Assert.NotNull(channel.Members.FirstOrDefault(member => member.User == otherUser));
102102

103103
await WaitWithTimeoutAsync(tcs.Task, 5, $"Event {nameof(channel.MessageReceived)} was not received");
@@ -124,12 +124,12 @@ private async Task When_remove_member_by_reference_to_channel_expect_member_remo
124124

125125
await channel.AddMembersAsync(hideHistory: default, optionalMessage: default, otherUser);
126126

127-
await WaitWhileConditionTrueAsync(() => channel.Members.All(m => m.User != otherUser));
127+
await WaitWhileTrueAsync(() => channel.Members.All(m => m.User != otherUser));
128128

129129
var otherUserMember = channel.Members.FirstOrDefault(m => m.User == otherUser);
130130

131131
await channel.RemoveMembersAsync(otherUserMember);
132-
await WaitWhileConditionTrueAsync(() => channel.Members.Any(m => m.User == otherUser));
132+
await WaitWhileTrueAsync(() => channel.Members.Any(m => m.User == otherUser));
133133
Assert.IsNull(channel.Members.FirstOrDefault(member => member.User == otherUser));
134134
}
135135

@@ -154,10 +154,10 @@ private async Task When_remove_member_by_user_id_to_channel_expect_member_remove
154154

155155
await channel.AddMembersAsync(hideHistory: default, optionalMessage: default, otherUser.Id);
156156

157-
await WaitWhileConditionTrueAsync(() => channel.Members.All(m => m.User != otherUser));
157+
await WaitWhileTrueAsync(() => channel.Members.All(m => m.User != otherUser));
158158

159159
await channel.RemoveMembersAsync(otherUser.Id);
160-
await WaitWhileConditionTrueAsync(() => channel.Members.Any(m => m.User == otherUser));
160+
await WaitWhileTrueAsync(() => channel.Members.Any(m => m.User == otherUser));
161161
Assert.IsNull(channel.Members.FirstOrDefault(member => member.User == otherUser));
162162
}
163163

@@ -238,7 +238,7 @@ private async Task When_add_members_expect_member_added_event_fired_Async()
238238

239239
await channel.AddMembersAsync(hideHistory: default, optionalMessage: default, user);
240240

241-
await WaitWhileConditionFalseAsync(() => receivedEvent && receivedEvent2);
241+
await WaitWhileFalseAsync(() => receivedEvent && receivedEvent2);
242242

243243
Assert.IsTrue(receivedEvent);
244244
Assert.IsNotNull(eventChannel);
@@ -288,7 +288,7 @@ private async Task When_remove_members_expect_member_added_event_fired_Async()
288288
await channel.AddMembersAsync(hideHistory: default, optionalMessage: default, user);
289289
await channel.RemoveMembersAsync(user);
290290

291-
await WaitWhileConditionFalseAsync(() => receivedEvent && receivedEvent2);
291+
await WaitWhileFalseAsync(() => receivedEvent && receivedEvent2);
292292

293293
Assert.IsTrue(receivedEvent);
294294
Assert.IsNotNull(eventChannel);

Assets/Plugins/StreamChat/Tests/StatefulClient/ChannelsTests.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ private async Task When_mute_channel_expect_muted_Async()
109109
await channel.MuteChannelAsync();
110110

111111
// Wait for data to propagate
112-
await WaitWhileConditionTrueAsync(() => Client.LocalUserData.ChannelMutes.Count == 0);
112+
await WaitWhileTrueAsync(() => Client.LocalUserData.ChannelMutes.Count == 0);
113113

114114
Assert.IsNotEmpty(Client.LocalUserData.ChannelMutes);
115115

@@ -141,7 +141,7 @@ private async Task When_unmute_muted_channel_expect_unmuted_Async()
141141

142142
await channel.UnmuteChannelAsync();
143143

144-
await WaitWhileConditionTrueAsync(() =>
144+
await WaitWhileTrueAsync(() =>
145145
{
146146
channelMute = Client.LocalUserData.ChannelMutes.FirstOrDefault(m => m.Channel == channel);
147147
return channelMute != null;
@@ -173,7 +173,7 @@ var response
173173
SkipThisTempChannelDeletionInTearDown(channel);
174174
SkipThisTempChannelDeletionInTearDown(channel2);
175175

176-
await WaitWhileConditionTrueAsync(
176+
await WaitWhileTrueAsync(
177177
() => Client.WatchedChannels.Contains(channel) || Client.WatchedChannels.Contains(channel2));
178178

179179
Assert.IsFalse(Client.WatchedChannels.Contains(channel));
@@ -192,11 +192,17 @@ private async Task When_truncate_channel_expect_messages_cleared_Async()
192192
await channel.SendNewMessageAsync("Hello 2");
193193
await channel.SendNewMessageAsync("Hello 3");
194194

195+
var cts = new TaskCompletionSource<bool>();
196+
channel.MessageReceived += (streamChannel, streamMessage) => cts.SetResult(true);
197+
195198
Assert.AreEqual(3, channel.Messages.Count);
196199

197200
var beforeDate = DateTimeOffset.UtcNow.AddHours(-1);
198201

199-
await channel.TruncateAsync(beforeDate, "Hi sorry for deleting all", isHardDelete: true);
202+
await channel.TruncateAsync(beforeDate, "Truncated everything from an hour ago", isHardDelete: true);
203+
204+
// Wait for message.received event
205+
await cts.Task;
200206

201207
//expect no messages removed + system message added
202208
Assert.AreEqual(4, channel.Messages.Count);
@@ -216,9 +222,12 @@ private async Task When_truncate_channel_with_system_message_expect_only_system_
216222

217223
Assert.AreEqual(3, channel.Messages.Count);
218224

219-
const string systemMessage = "Hi sorry for deleting all";
225+
const string systemMessage = "Hi, sorry for deleting all";
220226
await channel.TruncateAsync(systemMessage: systemMessage);
221227

228+
// Wait for truncated event to be received
229+
await WaitWhileTrueAsync(() => channel.Messages.Count != 1);
230+
222231
Assert.AreEqual(1, channel.Messages.Count);
223232
Assert.AreEqual(systemMessage, channel.Messages[0].Text);
224233
}
@@ -263,7 +272,7 @@ private async Task When_set_channel_custom_data_expect_data_set_on_channel_Async
263272
}
264273
});
265274

266-
await WaitWhileConditionFalseAsync(
275+
await WaitWhileFalseAsync(
267276
() => new[] { "owned_dogs", "breakfast", "clan_info" }.All(channel.CustomData.ContainsKey));
268277

269278
var ownedDogs = channel.CustomData.Get<int>("owned_dogs");
@@ -296,7 +305,7 @@ private async Task When_unset_channel_custom_data_expect_no_data_on_channel_obje
296305
}
297306
});
298307

299-
await WaitWhileConditionFalseAsync(
308+
await WaitWhileFalseAsync(
300309
() => new[] { "owned_dogs", "breakfast" }.All(channel.CustomData.ContainsKey));
301310

302311
var ownedDogs = channel.CustomData.Get<int>("owned_dogs");

Assets/Plugins/StreamChat/Tests/StatefulClient/MessagesTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public async Task When_message_soft_delete_message_expect_text_cleared_Async()
141141

142142
await messageInChannel.SoftDeleteAsync();
143143

144-
await WaitWhileConditionTrueAsync(() => !messageInChannel.DeletedAt.HasValue);
144+
await WaitWhileTrueAsync(() => !messageInChannel.DeletedAt.HasValue);
145145

146146
Assert.NotNull(messageInChannel);
147147
Assert.IsNotNull(messageInChannel.DeletedAt);
@@ -166,7 +166,7 @@ public async Task When_message_hard_delete_message_expect_message_removed_Async(
166166

167167
await messageInChannel.HardDeleteAsync();
168168

169-
await WaitWhileConditionTrueAsync(() => !messageInChannel.DeletedAt.HasValue);
169+
await WaitWhileTrueAsync(() => !messageInChannel.DeletedAt.HasValue);
170170

171171
messageInChannel = channel.Messages.FirstOrDefault(_ => _.Id == sentMessage.Id);
172172
Assert.IsNull(messageInChannel);

0 commit comments

Comments
 (0)