Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        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");
Ejemplo n.º 6
0
        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();
        }
Ejemplo n.º 7
0
        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();
            }
        }