WhenMessageReceived_WithNotMatchingDeltaFromProperty_ShouldStartDecodeRecoveryAndMoveToAttachingWithError() { var(realtime, c) = await GetClientAndChannel(); RealtimeChannel channel = (RealtimeChannel)c; channel.SetChannelState(ChannelState.Attached); var awaiter = new TaskCompletionAwaiter(); ChannelStateChange stateChange = null; channel.On(ChannelEvent.Attaching, change => { stateChange = change; channel.DecodeRecovery.Should().BeTrue(); awaiter.Done(); }); realtime.ExecuteCommand(ProcessMessageCommand.Create( new ProtocolMessage(ProtocolMessage.MessageAction.Message) { Channel = channel.Name, Messages = new[] { new Message { Extras = CreateExtrasWithDelta(new DeltaExtras("1", string.Empty)) }, }, })); await awaiter.Task; stateChange.Current.Should().Be(ChannelState.Attaching); stateChange.Error.Code.Should().Be(ErrorCodes.VcDiffDecodeError); }
internal async Task WhenClientIdChangesAfterRegisteringDevice_StateMachineShouldReceive_GotPushDeviceDetailsEvent() { // Arrange const string newClientId = "testId"; var options = new ClientOptions(ValidKey) { TransportFactory = new FakeTransportFactory(), SkipInternetCheck = true }; var mobileDevice = new FakeMobileDevice(); async Task <AblyResponse> HandleRequestFunc(AblyRequest request) { if (request.Url.Contains("/push/deviceRegistrations")) { return(new AblyResponse() { TextResponse = JObject.FromObject(new { clientId = newClientId, deviceIdentityToken = new { token = "token" } }).ToString() }); } return(new AblyResponse() { TextResponse = "{}" }); } var realtime = new AblyRealtime(options, (clientOptions, device) => GetRestClient(HandleRequestFunc, options, device), mobileDevice); // Setup the local device var localDevice = PushTestHelpers.GetRegisteredLocalDevice(realtime.RestClient); realtime.RestClient.Device = localDevice; localDevice.ClientId.Should().BeNull(); realtime.Push.InitialiseStateMachine(); var taskAwaiter = new TaskCompletionAwaiter(); var stateMachine = realtime.Push.StateMachine; stateMachine.CurrentState = new ActivationStateMachine.WaitingForPushDeviceDetails(stateMachine); // We trigger the GotPushDeviceDetails event await stateMachine.HandleEvent(new ActivationStateMachine.GotPushDeviceDetails()); // From here we expect the stateMachine to move to WaitingForDeviceRegistration and try to register the Device // The registration will hit our mocked rest client above and return a localDevice with a new clientId. // Once the clientId is received we should expect to receive GotPushDeviceDetails event and the new clientId to be persisted realtime.Push.StateMachine.ProcessingEventCallback = @event => { // Check we received the correct event @event.Should().BeOfType <ActivationStateMachine.GotPushDeviceDetails>(); taskAwaiter.Done(); }; (await taskAwaiter).Should().BeTrue(); mobileDevice.GetPreference(PersistKeys.Device.ClientId, PersistKeys.Device.SharedName).Should().Be(newClientId); }
public async Task ChannelWithDeltasEnabled_ShouldSupportProcessingMultipleMessagesInSamePayload(Protocol protocol) { string testName = "delta-channel".AddRandomSuffix(); var receivedMessages = new List <ProtocolMessage>(); var realtime = await GetRealtimeClient(protocol, (options, settings) => { var optionsTransportFactory = new TestTransportFactory { BeforeDataProcessed = receivedMessages.Add, }; options.TransportFactory = optionsTransportFactory; }); var channel = realtime.Channels.Get("[?delta=vcdiff]" + testName); var waitForDone = new TaskCompletionAwaiter(); var received = new List <Message>(); int count = 0; channel.Subscribe(message => { count++; received.Add(message); if (count == 3) { waitForDone.Done(); } }); channel.Error += (sender, args) => throw new Exception(args.Reason.Message); /* subscribe */ await channel.AttachAsync(); var testData = new[] { new TestData("bar", 1, "active"), new TestData("bar", 2, "active"), new TestData("bar", 3, "inactive"), }; await channel.PublishAsync(testData.Select(x => new Message(x.Count.ToString(), x))); await waitForDone; for (var i = 0; i < received.Count; i++) { var message = received[i]; var data = ((JToken)message.Data).ToObject <TestData>(); var original = testData[i]; Assert.Equal(data, original); } receivedMessages .Where(x => x.Action == ProtocolMessage.MessageAction.Message) .Should().HaveCount(1); }
internal async Task WhenClientIdChangesAfterInitialisation_StateMachineShouldReceive_GotPushDeviceDetailsEvent(Func <ActivationStateMachine, ActivationStateMachine.State> createCurrentState) { // Arrange const string initialClientId = "123"; var options = new ClientOptions(ValidKey) { TransportFactory = new FakeTransportFactory(), SkipInternetCheck = true, ClientId = initialClientId }; var mobileDevice = new FakeMobileDevice(); var realtime = new AblyRealtime(options, mobileDevice: mobileDevice); const string newClientId = "testId"; var localDevice = realtime.Device; // Make sure the LocalDevice is registered realtime.Device.DeviceIdentityToken = "token"; localDevice.ClientId.Should().Be(initialClientId); // Initialise the activation statemachine and set a fake state to record the next event. realtime.Push.InitialiseStateMachine(); var taskAwaiter = new TaskCompletionAwaiter(); realtime.Push.StateMachine.CurrentState = createCurrentState(realtime.Push.StateMachine); realtime.Push.StateMachine.ProcessingEventCallback = @event => { // Check we received the correct event @event.Should().BeOfType <ActivationStateMachine.GotPushDeviceDetails>(); taskAwaiter.Done(); }; // Pretend we are connected and change the ClientId realtime.FakeProtocolMessageReceived(new ProtocolMessage(ProtocolMessage.MessageAction.Connected) { ConnectionDetails = new ConnectionDetails { ClientId = newClientId }, }); await realtime.WaitForState(ConnectionState.Connected); // Check the clientId is set correctly realtime.Auth.ClientId.Should().Be(newClientId); localDevice.ClientId.Should().Be(newClientId); // It's necessary to pause the current thread and let the background action to complete which fires the event. await Task.Delay(100); (await taskAwaiter).Should().BeTrue(); mobileDevice.GetPreference(PersistKeys.Device.ClientId, PersistKeys.Device.SharedName).Should().Be(newClientId); }
WhenMultipleMessagesWithAMixOfNormalAndDeltaMessages_ShouldDecodeCorrectly() { using var logging = EnableDebugLogging(); var(realtime, c) = await GetClientAndChannel(); RealtimeChannel channel = (RealtimeChannel)c; channel.SetChannelState(ChannelState.Attached); List <Message> messages = new List <Message>(); var taskAwaiter = new TaskCompletionAwaiter(15000); channel.Subscribe(x => { messages.Add(x); if (messages.Count == 4) { taskAwaiter.Done(); } }); var protocolMessage = new ProtocolMessage(ProtocolMessage.MessageAction.Message) { Channel = channel.Name, Messages = new[] { CreateMessage("delta.1", false), CreateMessage("delta.1.vcdiff", true), CreateMessage("delta.2.vcdiff", true), CreateMessage("delta.3.vcdiff", true), }, }; await realtime.ProcessMessage(protocolMessage); await realtime.ProcessCommands(); var result = await taskAwaiter; result.Should().BeTrue("Four messages should have been received."); messages[0].Data.Should().BeOfType <string>(); IsCorrectFile(((string)messages[0].Data).GetBytes(), "delta.1"); messages[1].Data.Should().BeOfType <byte[]>(); IsCorrectFile((byte[])messages[1].Data, "delta.2"); messages[2].Data.Should().BeOfType <byte[]>(); IsCorrectFile((byte[])messages[2].Data, "delta.3"); messages[3].Data.Should().BeOfType <byte[]>(); IsCorrectFile((byte[])messages[3].Data, "delta.4");
internal async Task WhenClientIdChangesAfterInitialisationAndStateMachineIsNotActivated_ShouldNotFireEvent() { // Arrange const string initialClientId = "123"; var options = new ClientOptions(ValidKey) { TransportFactory = new FakeTransportFactory(), SkipInternetCheck = true, ClientId = initialClientId }; var mobileDevice = new FakeMobileDevice(); var realtime = new AblyRealtime(options, mobileDevice: mobileDevice); const string newClientId = "testId"; var localDevice = realtime.Device; // Make sure the LocalDevice is registered realtime.Device.DeviceIdentityToken = "token"; localDevice.ClientId.Should().Be(initialClientId); realtime.Push.InitialiseStateMachine(); var taskAwaiter = new TaskCompletionAwaiter(1000); realtime.Push.StateMachine.ProcessingEventCallback = @event => { taskAwaiter.Done(); }; // Pretend we are connected and change the ClientId realtime.FakeProtocolMessageReceived(new ProtocolMessage(ProtocolMessage.MessageAction.Connected) { ConnectionDetails = new ConnectionDetails { ClientId = newClientId }, }); await realtime.WaitForState(ConnectionState.Connected); // It's necessary to pause the current thread and let the background action to complete which fires the event. await Task.Delay(100); // No event should be sent to the statemachine (await taskAwaiter).Should().BeFalse(); }
public async Task WhenDeltaDecodeFail_ShouldSetStateToAttachingLogTheErrorAndDiscardTheMessage(Protocol protocol) { string channelName = "delta-channel".AddRandomSuffix(); var testSink = new TestLoggerSink(); var taskAwaiter = new TaskCompletionAwaiter(5000); var firstMessageReceived = new TaskCompletionAwaiter(); using (((IInternalLogger)Logger).CreateDisposableLoggingContext(testSink)) { var realtime = await GetRealtimeClient(protocol); var channel = realtime.Channels.Get(channelName, new ChannelOptions(channelParams: new ChannelParams { { "delta", "vcdiff" } })); var received = new List <Message>(); channel.Subscribe(message => { received.Add(message); if (received.Count == 1) { firstMessageReceived.Done(); } if (received.Count == 2) { taskAwaiter.Done(); } }); await channel.AttachAsync(); // We wait for the first message to be acknowledged. Any consequent messages will be deltas await channel.PublishAsync("firstMessage", new TestData("bar", 1, "active")); (await firstMessageReceived).Should().BeTrue("First message should be received before continuing with broken message"); channel.Publish("second", "second message"); // We don't want to wait for the acknowledgement realtime.ExecuteCommand(ProcessMessageCommand.Create(new ProtocolMessage(ProtocolMessage.MessageAction.Message) { Channel = channelName, Messages = new[] { new Message { Id = "badMessage", Encoding = "vcdiff", Data = Array.Empty <byte>() }, }, })); await channel.WaitForState(ChannelState.Attaching); await channel.WaitForAttachedState(); var result = await taskAwaiter; result.Should().BeTrue("TaskAwaiter Done() Should be called."); received.Should().HaveCount(2); received[1].Data.Should().Be("second message"); // RTL17 - we make sure the message is not emitted to subscribers received.Should().NotContain(x => x.Id == "badMessage"); bool hasVcdiffErrorMessage = testSink.Messages.Any(x => x.StartsWith(LogLevel.Error.ToString()) && x.Contains(ErrorCodes.VcDiffDecodeError .ToString())); hasVcdiffErrorMessage.Should().BeTrue(); } }