Esempio n. 1
0
        public static async Task WaitFor(int timeoutMs, int taskCount, Action <Action> action, Action onFail = null)
        {
            var tsc = new TaskCompletionAwaiter(timeoutMs, taskCount);

            void Done()
            {
                tsc.Tick();
            }

            action(Done);
            var success = await tsc.Task;

            if (!success)
            {
                var msg = $"Timeout of {timeoutMs}ms exceeded.";
                if (taskCount > 1)
                {
                    msg += $" Completed {taskCount - tsc.TaskCount} of {taskCount} tasks.";
                }

                onFail?.Invoke();

                throw new Exception(msg);
            }
        }
Esempio n. 2
0
        public async Task WhenFakeDisconnectedMessageContainsTokenError_ForcesClientToReauthenticate(Protocol protocol)
        {
            var reconnectAwaiter = new TaskCompletionAwaiter();
            var client           = await GetRealtimeClient(protocol, (options, settings) =>
            {
                options.UseTokenAuth = true;
            });

            await client.WaitForState(ConnectionState.Connected);

            var initialToken = client.RestClient.AblyAuth.CurrentToken;

            client.Connection.Once(ConnectionEvent.Disconnected, state2 =>
            {
                client.Connection.Once(ConnectionEvent.Connected, state3 =>
                {
                    reconnectAwaiter.SetCompleted();
                });
            });

            client.FakeProtocolMessageReceived(new ProtocolMessage(ProtocolMessage.MessageAction.Disconnected)
            {
                Error = new ErrorInfo("testing RTN22a", ErrorCodes.TokenError)
            });
            var didReconnect = await reconnectAwaiter.Task;

            didReconnect.Should().BeTrue();
            client.RestClient.AblyAuth.CurrentToken.Should().NotBe(initialToken);
            client.Close();
        }
Esempio n. 3
0
        public async Task WhenWebSocketClientIsNull_SendShouldSetDisconnectedState(Protocol protocol)
        {
            var client = await GetRealtimeClient(protocol);

            await WaitForState(client); //wait for connection

            client.Connection.State.Should().Be(ConnectionState.Connected);

            var transportWrapper = client.ConnectionManager.Transport as TestTransportWrapper;

            transportWrapper.Should().NotBe(null);
            var wsTransport = transportWrapper._wrappedTransport as MsWebSocketTransport;

            wsTransport.Should().NotBe(null);
            wsTransport._socket.ClientWebSocket = null;

            var tca = new TaskCompletionAwaiter();

            client.Connection.On(s =>
            {
                if (s.Current == ConnectionState.Disconnected)
                {
                    tca.SetCompleted();
                }
            });

            await client.Channels.Get("test").PublishAsync("event", "data");

            await tca.Task;

            // should auto connect again
            await WaitForState(client);
        }
Esempio n. 4
0
        public IEnumerator RealTimeWithAuthUrl_WhenTokenExpired_ShouldRetry_WhenRetryFails_ShouldSetError([ValueSource(nameof(_protocols))] Protocol protocol)
        {
            return(UniTask.ToCoroutine(async() =>
            {
                var authRestClient = await AblySandbox.GetRestClient(protocol);
                var token = await authRestClient.Auth.RequestTokenAsync(new TokenParams
                {
                    Ttl = TimeSpan.FromMilliseconds(1000)
                });

                // this realtime client will have a key for the sandbox, thus a means to renew
                var realtimeClient = await AblySandbox.GetRealtimeClient(protocol, (options, _) =>
                {
                    options.TokenDetails = token;
                    options.AuthUrl = new Uri(_errorUrl);
                    options.AutoConnect = false;
                });

                var awaiter = new TaskCompletionAwaiter(5000);
                realtimeClient.Connection.Once(ConnectionEvent.Disconnected, state =>
                {
                    state.Reason.Code.Should().Be(ErrorCodes.ClientAuthProviderRequestFailed);
                    awaiter.SetCompleted();
                });

                await Task.Delay(2000);
                realtimeClient.Connect();

                var result = await awaiter.Task;
                result.Should().BeTrue();
            }));
        }
Esempio n. 5
0
        public async Task WithAConnectionError_ShouldRaiseChangeStateEventWithError()
        {
            var client = GetClientWithFakeTransport();

            ConnectionStateChange stateChange = null;
            var awaiter = new TaskCompletionAwaiter();

            client.Connection.On(ConnectionEvent.Failed, state =>
            {
                stateChange = state;
                awaiter.Tick();
            });

            var expectedError = new ErrorInfo("fake error");

            client.FakeProtocolMessageReceived(
                new ProtocolMessage(ProtocolMessage.MessageAction.Error)
            {
                Error = expectedError
            });

            await awaiter.Task;

            stateChange.HasError.Should().BeTrue();
            stateChange.Reason.Should().Be(expectedError);

            // RTN14g, expect FAILED
            stateChange.Event.Should().Be(ConnectionEvent.Failed);
        }
Esempio n. 6
0
        public async Task Auth_WithRealtimeClient_WhenAuthFails_ShouldTransitionToOrRemainInTheCorrectState(Protocol protocol)
        {
            async Task TestConnectingBecomesDisconnected(string context, Action <ClientOptions, TestEnvironmentSettings> optionsAction)
            {
                TaskCompletionAwaiter tca = new TaskCompletionAwaiter(5000);
                var realtimeClient        = await GetRealtimeClient(protocol, optionsAction);

                realtimeClient.Connection.On(ConnectionEvent.Disconnected, change =>
                {
                    change.Previous.Should().Be(ConnectionState.Connecting);
                    change.Reason.Code.Should().Be(ErrorCodes.ClientAuthProviderRequestFailed);
                    tca.SetCompleted();
                });

                realtimeClient.Connection.Connect();
                await realtimeClient.ProcessCommands();

                (await tca.Task).Should().BeTrue(context);
            }

            // authUrl fails
            void AuthUrlOptions(ClientOptions options, TestEnvironmentSettings settings)
            {
                options.AutoConnect            = false;
                options.AuthUrl                = new Uri(ErrorUrl);
                options.RealtimeRequestTimeout = TimeSpan.FromSeconds(2);
                options.HttpRequestTimeout     = TimeSpan.FromSeconds(2);
            }
Esempio n. 7
0
            public async Task SubscribeDevice_ShouldUsePushDeviceAuthentication()
            {
                const string deviceIdentityToken = "identityToken";
                var          taskAwaiter         = new TaskCompletionAwaiter();

                async Task <AblyResponse> RequestHandler(AblyRequest request)
                {
                    request.Headers.Should().ContainKey(Defaults.DeviceIdentityTokenHeader).WhoseValue.Should()
                    .Be(deviceIdentityToken);

                    taskAwaiter.SetCompleted();
                    return(new AblyResponse()
                    {
                        TextResponse = JsonConvert.SerializeObject(new PushChannelSubscription())
                    });
                }

                var client = GetRestClient(RequestHandler, mobileDevice: new FakeMobileDevice());

                client.Device = new LocalDevice()
                {
                    Id = "id",
                    DeviceIdentityToken = deviceIdentityToken
                };

                var pushChannel = client.Channels.Get("test").Push;

                await pushChannel.SubscribeDevice();

                (await taskAwaiter).Should().BeTrue("Didn't validate function");
            }
Esempio n. 8
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);
        }
Esempio n. 9
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);
        }
Esempio n. 10
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);
        }
Esempio n. 11
0
        public async Task WhenConnectedMessageReceived_ShouldEmitUpdate(Protocol protocol)
        {
            var updateAwaiter = new TaskCompletionAwaiter(5000);
            var client        = await GetRealtimeClient(protocol, (options, settings) =>
            {
                options.UseTokenAuth = true;
                options.AutoConnect  = true;
            });

            await client.WaitForState(ConnectionState.Connected);

            client.Connection.ConnectionStateTtl.Should().NotBe(TimeSpan.MaxValue);

            var key = client.Connection.Key;

            client.Connection.Once(state =>
            {
                // RTN4h - can emit UPDATE event
                if (state.Event == ConnectionEvent.Update)
                {
                    // should have both previous and current attributes set to CONNECTED
                    state.Current.Should().Be(ConnectionState.Connected);
                    state.Previous.Should().Be(ConnectionState.Connected);
                    state.Reason.Message = "fake-error";
                    updateAwaiter.SetCompleted();
                }
                else
                {
                    throw new Exception($"'{state.Event}' was handled. Only an 'Update' event should have occured");
                }
            });

            client.FakeProtocolMessageReceived(new ProtocolMessage(ProtocolMessage.MessageAction.Connected)
            {
                ConnectionDetails = new ConnectionDetails
                {
                    ConnectionKey      = "key",
                    ClientId           = "RTN21",
                    ConnectionStateTtl = TimeSpan.MaxValue
                },
                Error = new ErrorInfo("fake-error"),
            });

            var didUpdate = await updateAwaiter.Task;

            didUpdate.Should().BeTrue();

            // RTN21 - new connection details over write old values
            client.Connection.Key.Should().NotBe(key);
            client.ClientId.Should().Be("RTN21");
            client.Connection.ConnectionStateTtl.Should().Be(TimeSpan.MaxValue);
        }
Esempio n. 12
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);
        }
Esempio n. 13
0
        public async Task WithTokenErrorAndTokenRenewalFails_ShouldRaiseErrorAndTransitionToDisconnected()
        {
            var tokenDetails = new TokenDetails("id")
            {
                Expires = Now.AddHours(1)
            };
            var taskAwaiter = new TaskCompletionAwaiter(taskCount: 2);
            var client      = GetClientWithFakeTransport(
                opts =>
            {
                opts.TokenDetails      = tokenDetails;
                opts.UseBinaryProtocol = false;
            }, request =>
            {
                if (request.Url.Contains("/keys"))
                {
                    throw new AblyException(new ErrorInfo {
                        Code = ErrorCodes.TokenError
                    });
                }

                return(AblyResponse.EmptyResponse.ToTask());
            });

            var stateChanges = new List <ConnectionStateChange>();

            client.Connection.On(stateChange =>
            {
                if (stateChange.Current == ConnectionState.Disconnected)
                {
                    taskAwaiter.Tick();
                }

                stateChanges.Add(stateChange);
            });

            await client.WaitForState(ConnectionState.Connecting);

            client.FakeProtocolMessageReceived(new ProtocolMessage(ProtocolMessage.MessageAction.Error)
            {
                Error = new ErrorInfo("Unauthorised", ErrorCodes.TokenError, HttpStatusCode.Unauthorized)
            });

            await taskAwaiter.Task;

            stateChanges.Count.Should().BeGreaterThan(0);
            client.Connection.ErrorReason.Should().NotBeNull();
            client.Connection.ErrorReason.Code.Should().Be(ErrorCodes.TokenError);
        }
Esempio n. 14
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");
Esempio n. 15
0
            public async Task WhenSendingMessage_AckCallbackCalled_ForMultipleMessages()
            {
                // Arrange
                var client = await GetConnectedClient();

                var callbacks = new List <ValueTuple <bool, ErrorInfo> >();

                var message1 = new ProtocolMessage(ProtocolMessage.MessageAction.Message, "Test");
                var message2 = new ProtocolMessage(ProtocolMessage.MessageAction.Message, "Test");
                var message3 = new ProtocolMessage(ProtocolMessage.MessageAction.Message, "Test");

                var awaiter = new TaskCompletionAwaiter();

                Action <bool, ErrorInfo> GetCallback(int forCount) =>
                (ack, err) =>
                {
                    if (callbacks.Count == forCount)
                    {
                        callbacks.Add((ack, err));
                    }

                    if (callbacks.Count == 3)
                    {
                        awaiter.SetCompleted();
                    }
                };

                var ackMessage = new ProtocolMessage(ProtocolMessage.MessageAction.Ack)
                {
                    MsgSerial = 0, Count = 3
                };

                // Act
                client.Workflow.QueueAck(message1, GetCallback(0));
                client.Workflow.QueueAck(message2, GetCallback(1));
                client.Workflow.QueueAck(message3, GetCallback(2));
                client.ExecuteCommand(ProcessMessageCommand.Create(ackMessage));

                await client.ProcessCommands();

                await awaiter.Task;

                // Assert
                callbacks.Count.Should().Be(3);
                Assert.True(callbacks.TrueForAll(c => c.Item1));         // Ack
                Assert.True(callbacks.TrueForAll(c => c.Item2 == null)); // No error
            }
Esempio n. 16
0
        public async Task WithConnectedClient_AuthorizeObtainsNewTokenAndUpgradesConnection_AndShouldEmitUpdate(Protocol protocol)
        {
            const string validClientId1  = "RTC8";
            const string invalidClientId = "RTC8-incompatible-clientId";

            // For a realtime client, Auth#authorize instructs the library to obtain
            // a token using the provided tokenParams and authOptions and upgrade
            // the current connection to use that token
            var client = await GetRealtimeClient(protocol, (opts, _) =>
            {
                opts.ClientId     = validClientId1;
                opts.UseTokenAuth = true;
            });

            var awaiter = new TaskCompletionAwaiter();

            client.Connection.On(ConnectionEvent.Update, args => { awaiter.SetCompleted(); });
            await client.WaitForState(ConnectionState.Connected);

            var tokenDetails = await client.Auth.AuthorizeAsync(new TokenParams { ClientId = validClientId1 });

            tokenDetails.ClientId.Should().Be(validClientId1);
            client.Connection.State.Should().Be(ConnectionState.Connected);
            client.RestClient.AblyAuth.CurrentToken.Should().Be(tokenDetails);
            var didUpdate = await awaiter.Task;

            client.Connection.State.Should().Be(ConnectionState.Connected);
            didUpdate.Should().BeTrue(
                "the AUTH message should trigger a CONNECTED response from the server that causes an UPDATE to be emitted.");

            client.Connection.On(args =>
            {
                if (args.Current != ConnectionState.Failed)
                {
                    Assert.True(false, $"unexpected state '{args.Current}'");
                }
            });

            // AuthorizeAsync will not return until either a CONNECTED or ERROR response
            // (or timeout) is seen from Ably, so we do not need to use WaitForState() here
            await Assert.ThrowsAsync <AblyException>(() => client.Auth.AuthorizeAsync(new TokenParams {
                ClientId = invalidClientId
            }));

            client.Connection.State.Should().Be(ConnectionState.Failed);
        }
Esempio n. 17
0
        WhenMessageReceivedAndFailsVcdiffDecoding_ShouldSendAttachProtocolMessageWithLastSuccessfulChannelSerial()
        {
            var(realtime, c) = await GetClientAndChannel();

            RealtimeChannel channel = (RealtimeChannel)c;

            channel.SetChannelState(ChannelState.Attached);

            var successfulProtocolMessage = new ProtocolMessage(ProtocolMessage.MessageAction.Message)
            {
                Channel       = channel.Name,
                ChannelSerial = "testSerial",
                Messages      = new[] { new Message {
                                            Data = "test", Encoding = string.Empty
                                        }, },
            };

            realtime.ExecuteCommand(ProcessMessageCommand.Create(successfulProtocolMessage));

            var awaiter = new TaskCompletionAwaiter();

            channel.On(ChannelEvent.Attaching, change => { awaiter.Tick(); });

            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;
            await realtime.ProcessCommands();

            var fakeTransport   = FakeTransportFactory.LastCreatedTransport;
            var lastMessageSend = fakeTransport.LastMessageSend;

            lastMessageSend.Should().NotBeNull();
            lastMessageSend.Action.Should().Be(ProtocolMessage.MessageAction.Attach);
            lastMessageSend.ChannelSerial.Should().Be("testSerial");
        }
Esempio n. 18
0
            public async Task ListSubscriptions_ShouldCallApiWithCorrectParameters()
            {
                const string channelName         = "testChannel";
                const string clientId            = "clientId";
                const string deviceid            = "deviceId";
                const string deviceIdentityToken = "token";

                var taskAwaiter = new TaskCompletionAwaiter();

                async Task <AblyResponse> RequestHandler(AblyRequest request)
                {
                    request.Url.Should().Be("/push/channelSubscriptions");
                    request.Method.Should().Be(HttpMethod.Get);
                    var queryParams = request.QueryParameters;

                    queryParams.Should().ContainKey("clientId").WhoseValue.Should().Be(clientId);
                    queryParams.Should().ContainKey("channel").WhoseValue.Should().Be(channelName);
                    queryParams.Should().ContainKey("deviceId").WhoseValue.Should().Be(deviceid);
                    queryParams.Should().ContainKey("concatFilters").WhoseValue.Should().Be("true");

                    taskAwaiter.SetCompleted();
                    return(new AblyResponse {
                        TextResponse = JsonConvert.SerializeObject(new List <PushChannelSubscription>())
                    });
                }

                var client = GetRestClient(RequestHandler, mobileDevice: new FakeMobileDevice());

                client.Device = new LocalDevice()
                {
                    DeviceIdentityToken = deviceIdentityToken,
                    ClientId            = clientId,
                    Id = deviceid
                };

                var pushChannel = client.Channels.Get(channelName).Push;

                var subscriptions = await pushChannel.ListSubscriptions();

                subscriptions.Should().NotBeNull();

                (await taskAwaiter).Should().BeTrue("Didn't validate function");
            }
Esempio n. 19
0
            public async Task UnsubscribeDevice_ShouldSendADeleteRequestTo_PushChannelSubscriptions_WithCorrectParameters_And_AuthHeader()
            {
                const string channelName         = "testChannel";
                const string deviceId            = "deviceId";
                const string deviceIdentityToken = "token";

                var taskAwaiter = new TaskCompletionAwaiter();

                async Task <AblyResponse> RequestHandler(AblyRequest request)
                {
                    // RSH7c2, check the correct request is made
                    request.Url.Should().Be("/push/channelSubscriptions");
                    request.Method.Should().Be(HttpMethod.Delete);
                    var queryParams = request.QueryParameters;

                    queryParams.Should().ContainKey("deviceId").WhoseValue.Should().Be(deviceId);
                    queryParams.Should().ContainKey("channel").WhoseValue.Should().Be(channelName);
                    queryParams.Should().NotContainKey("clientId");

                    // Check the auth header RSH7c3
                    request.Headers.Should().ContainKey(Defaults.DeviceIdentityTokenHeader).WhoseValue.Should()
                    .Be(deviceIdentityToken);

                    taskAwaiter.SetCompleted();
                    return(new AblyResponse()
                    {
                        TextResponse = JsonConvert.SerializeObject(new PushChannelSubscription())
                    });
                }

                var client = GetRestClient(RequestHandler, mobileDevice: new FakeMobileDevice());

                client.Device = new LocalDevice()
                {
                    Id = deviceId,
                    DeviceIdentityToken = deviceIdentityToken
                };
                var pushChannel = client.Channels.Get(channelName).Push;

                await pushChannel.UnsubscribeDevice();

                (await taskAwaiter).Should().BeTrue("Didn't validate function");
            }
Esempio n. 20
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();
        }
Esempio n. 21
0
        public async Task RealTimeWithAuthCallback_WhenTokenExpired_ShouldRetry_WhenRetryFails_ShouldSetError(Protocol protocol)
        {
            // create a short lived token
            var authRestClient = await GetRestClient(protocol);

            var token = await authRestClient.Auth.RequestTokenAsync(new TokenParams
            {
                Ttl = TimeSpan.FromMilliseconds(1000),
            });

            bool didRetry       = false;
            var  realtimeClient = await GetRealtimeClient(protocol, (options, _) =>
            {
                options.TokenDetails = token;
                options.AuthCallback = tokenParams =>
                {
                    didRetry = true;
                    throw new Exception("AuthCallback failed");
                };
                options.AutoConnect = false;
            });

            var awaiter = new TaskCompletionAwaiter(5000);

            realtimeClient.Connection.Once(ConnectionEvent.Disconnected, state =>
            {
                state.Reason.Code.Should().Be(ErrorCodes.ClientAuthProviderRequestFailed);
                awaiter.SetCompleted();
            });

            await Task.Delay(2000);

            realtimeClient.Connect();

            var result = await awaiter.Task;

            result.Should().BeTrue();
            didRetry.Should().BeTrue();
        }
Esempio n. 22
0
        public async Task WhenDisconnectedMessageContainsTokenError_ForcesClientToReauthenticate(Protocol protocol)
        {
            var authClient = await GetRestClient(protocol);

            var reconnectAwaiter = new TaskCompletionAwaiter(60000);
            var client           = await GetRealtimeClient(protocol, (options, settings) =>
            {
                options.AuthCallback = tokenParams =>
                {
                    var results = authClient.AblyAuth.RequestToken(new TokenParams {
                        ClientId = "RTN22a", Ttl = TimeSpan.FromSeconds(35)
                    });
                    return(Task.FromResult <object>(results));
                };
                options.ClientId = "RTN22a";
            });

            await client.WaitForState(ConnectionState.Connected);

            var initialToken = client.RestClient.AblyAuth.CurrentToken;

            client.Connection.Once(ConnectionEvent.Disconnected, state2 =>
            {
                client.Connection.Once(ConnectionEvent.Connected, state3 =>
                {
                    reconnectAwaiter.SetCompleted();
                });
            });

            client.FakeProtocolMessageReceived(new ProtocolMessage(ProtocolMessage.MessageAction.Disconnected)
            {
                Error = new ErrorInfo("testing RTN22a", ErrorCodes.TokenError)
            });
            var didReconnect = await reconnectAwaiter.Task;

            didReconnect.Should().BeTrue();
            client.RestClient.AblyAuth.CurrentToken.Should().NotBe(initialToken);
            client.Close();
        }
Esempio n. 23
0
            public async Task ShouldSuccessfullyPublishAPayload(Protocol protocol)
            {
                // Arrange
                var client = await GetRealtimeClient(protocol);

                var channelName = "pushenabled:test".AddRandomSuffix();

                var channel = client.Channels.Get(channelName);
                await channel.AttachAsync();

                var pushPayload   = JObject.FromObject(new { notification = new { title = "test", body = "message body" }, data = new { foo = "bar" }, });
                var pushRecipient = JObject.FromObject(new
                {
                    transportType = "ablyChannel",
                    channel       = channelName,
                    ablyKey       = client.Options.Key,
                    ablyUrl       = "https://" + client.Options.FullRestHost(),
                });

                var awaiter = new TaskCompletionAwaiter();

                channel.Subscribe(message =>
                {
                    // Assert
                    message.Name.Should().Be("__ably_push__");
                    var payload = JObject.Parse((string)message.Data);
                    payload["data"].Should().BeEquivalentTo(pushPayload["data"]);
                    ((string)payload["notification"]["title"]).Should().Be("test");
                    ((string)payload["notification"]["body"]).Should().Be("message body");

                    awaiter.SetCompleted();
                });

                // Act
                await client.Push.Admin.PublishAsync(pushRecipient, pushPayload);

                // Wait for 10 seconds for awaiter.SetCompleted() and make sure it was called.
                (await awaiter.Task).Should().BeTrue();
            }
Esempio n. 24
0
        /// <summary>
        /// This method yields the current thread and waits until the whole command queue is processed.
        /// </summary>
        /// <returns></returns>
        public static async Task ProcessCommands(this IRealtimeClient client)
        {
            var realtime    = (AblyRealtime)client;
            var taskAwaiter = new TaskCompletionAwaiter();

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            _ = Task.Run(async() =>
            {
                while (true)
                {
                    await Task.Delay(50);

                    if (realtime.Workflow.IsProcessingCommands() == false)
                    {
                        taskAwaiter.SetCompleted();
                    }
                }
            });
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

            await taskAwaiter.Task;
        }
Esempio n. 25
0
        public IEnumerator RealtimeWithAuthError_WhenTokenExpired_ShouldRetry_WhenRetryFails_ShouldSetError([ValueSource(nameof(_protocols))] Protocol protocol)
        {
            return(UniTask.ToCoroutine(async() =>
            {
                var helper = new RSA4Helper(this);

                var restClient = await AblySandbox.GetRestClient(protocol);
                var token = await restClient.Auth.AuthorizeAsync(new TokenParams
                {
                    Ttl = TimeSpan.FromMilliseconds(1000),
                });

                // this realtime client will have a key for the sandbox, thus a means to renew
                var realtimeClient = await AblySandbox.GetRealtimeClient(protocol, (options, _) =>
                {
                    options.TokenDetails = token;
                    options.AutoConnect = false;
                });

                realtimeClient.RestClient.ExecuteHttpRequest = helper.AblyResponseWith500Status;

                var awaiter = new TaskCompletionAwaiter(5000);

                realtimeClient.Connection.Once(ConnectionEvent.Disconnected, state =>
                {
                    state.Reason.Code.Should().Be(ErrorCodes.ClientAuthProviderRequestFailed);
                    awaiter.SetCompleted();
                });

                await Task.Delay(2000);
                realtimeClient.Connect();

                var result = await awaiter.Task;
                result.Should().BeTrue();
                helper.Requests.Count.Should().Be(1);
                helper.Requests[0].Url.EndsWith("requestToken").Should().BeTrue();
            }));
        }
Esempio n. 26
0
            public async Task SubscribeChannel_ShouldSendARequestTo_PushChannelSubscriptions_WithCorrectParameters()
            {
                const string channelName = "testChannel";
                const string clientId    = "client101";

                var taskAwaiter = new TaskCompletionAwaiter();

                async Task <AblyResponse> RequestHandler(AblyRequest request)
                {
                    request.Url.Should().Be("/push/channelSubscriptions");
                    var postData = (PushChannelSubscription)request.PostData;

                    postData.Should().NotBeNull();
                    postData.Channel.Should().Be(channelName);
                    postData.ClientId.Should().Be(clientId);
                    postData.DeviceId.Should().BeNullOrEmpty();

                    taskAwaiter.SetCompleted();
                    return(new AblyResponse()
                    {
                        TextResponse = JsonConvert.SerializeObject(new PushChannelSubscription())
                    });
                }

                var client = GetRestClient(RequestHandler, mobileDevice: new FakeMobileDevice());

                client.Device = new LocalDevice()
                {
                    ClientId            = clientId,
                    DeviceIdentityToken = "identityToken"
                };
                var pushChannel = client.Channels.Get(channelName).Push;

                await pushChannel.SubscribeClient();

                (await taskAwaiter).Should().BeTrue("Didn't validate function");
            }
Esempio n. 27
0
        public IEnumerator Auth_WithRealtimeClient_WhenAuthFails_ShouldTransitionToOrRemainInTheCorrectState([ValueSource(nameof(_protocols))] Protocol protocol)
        {
            return(UniTask.ToCoroutine(async() =>
            {
                async Task TestConnectingBecomesDisconnected(string context, Action <ClientOptions, TestEnvironmentSettings> optionsAction)
                {
                    TaskCompletionAwaiter tca = new TaskCompletionAwaiter(5000);
                    var realtimeClient = await AblySandbox.GetRealtimeClient(protocol, optionsAction);
                    realtimeClient.Connection.On(ConnectionEvent.Disconnected, change =>
                    {
                        change.Previous.Should().Be(ConnectionState.Connecting);
                        change.Reason.Code.Should().Be(ErrorCodes.ClientAuthProviderRequestFailed);
                        tca.SetCompleted();
                    });

                    realtimeClient.Connection.Connect();
                    await realtimeClient.ProcessCommands();

                    (await tca.Task).Should().BeTrue(context);
                }

                // authUrl fails
                void AuthUrlOptions(ClientOptions options, TestEnvironmentSettings settings)
                {
                    options.AutoConnect = false;
                    options.AuthUrl = new Uri(_errorUrl);
                    options.RealtimeRequestTimeout = TimeSpan.FromSeconds(2);
                    options.HttpRequestTimeout = TimeSpan.FromSeconds(2);
                }

                // authCallback fails
                static void AuthCallbackOptions(ClientOptions options, TestEnvironmentSettings settings)
                {
                    options.AutoConnect = false;
                    options.AuthCallback = (tokenParams) => throw new Exception("AuthCallback force error");
                }
Esempio n. 28
0
        public async Task WithConnectedClient_WhenDowngradingCapabilities_ChannelShouldBecomeFailed(Protocol protocol)
        {
            var clientId         = "RTC8a1-downgrade".AddRandomSuffix();
            var channelName      = "RTC8a1-downgrade-channel".AddRandomSuffix();
            var wrongChannelName = "wrong".AddRandomSuffix();

            var(realtime, channel) = await SetupRealtimeClient();

            channel.On(statechange => Output.WriteLine($"Changed state: {statechange.Previous} to {statechange.Current}. Error: {statechange.Error}"));
            realtime.Connection.Once(ConnectionEvent.Disconnected, change => throw new Exception("Should not require a disconnect"));

            var result = await channel.PublishAsync("test", "should-not-fail");

            result.IsSuccess.Should().BeTrue();

            ChannelStateChange stateChange = null;

            var failedAwaiter = new TaskCompletionAwaiter(2000);

            channel.Once(ChannelEvent.Failed, state =>
            {
                stateChange = state;
                failedAwaiter.SetCompleted();
            });
            await DowngradeCapability(realtime);

            await channel.WaitForState(ChannelState.Failed, TimeSpan.FromSeconds(6));

            await failedAwaiter.Task;

            stateChange.Should().NotBeNull("channel should have failed");
            stateChange.Error.Code.Should().Be(ErrorCodes.OperationNotPermittedWithCapability);
            stateChange.Error.Message.Should().Contain("Channel denied access");

            async Task DowngradeCapability(AblyRealtime rt)
            {
                var capability = new Capability();

                capability.AddResource(wrongChannelName).AllowSubscribe();

                var newToken = await rt.Auth.AuthorizeAsync(new TokenParams
                {
                    Capability = capability,
                    ClientId   = clientId,
                });

                newToken.Should().NotBeNull();
            }

            async Task <(AblyRealtime, IRealtimeChannel)> SetupRealtimeClient()
            {
                var capability = new Capability();

                capability.AddResource(channelName).AllowAll();

                var restClient = await GetRestClient(protocol);

                var tokenDetails = await restClient.Auth.RequestTokenAsync(new TokenParams
                {
                    ClientId   = clientId,
                    Capability = capability
                });

                var rt = await GetRealtimeClient(protocol, (opts, _) => { opts.Token = tokenDetails.Token; });

                await rt.WaitForState(ConnectionState.Connected);

                var ch = rt.Channels.Get(channelName);
                await ch.AttachAsync();

                return(rt, ch);
            }
        }
Esempio n. 29
0
        public async Task WithConnectedClient_WhenUpgradingCapabilities_ConnectionShouldNotBeImpaired(Protocol protocol)
        {
            var clientId   = "RTC8a1".AddRandomSuffix();
            var capability = new Capability();

            capability.AddResource("foo").AllowPublish();

            var restClient = await GetRestClient(protocol, options => { options.UseTokenAuth = true; });

            var tokenDetails = await restClient.Auth.RequestTokenAsync(new TokenParams
            {
                ClientId   = clientId,
                Capability = capability,
            });

            var realtime = await GetRealtimeClient(protocol, (opts, _) =>
            {
                opts.Token = tokenDetails.Token;
            });

            await realtime.WaitForState();

            // upgrade of capabilities without any loss of continuity or connectivity
            realtime.Connection.Once(ConnectionEvent.Disconnected, change => throw new Exception("should not disconnect"));

            var fooChannel = realtime.Channels.Get("foo");
            var barChannel = realtime.Channels.Get("bar");

            var fooSuccessAWaiter = new TaskCompletionAwaiter(5000);

            fooChannel.Publish("test", "should-not-fail", (b, info) =>
            {
                // foo should succeed
                b.Should().BeTrue();
                info.Should().BeNull();
                fooSuccessAWaiter.SetCompleted();
            });
            fooChannel.Attach();
            Assert.True(await fooSuccessAWaiter.Task);

            var barFailAwaiter = new TaskCompletionAwaiter(5000);

            barChannel.Publish("test", "should-fail", (b, info) =>
            {
                // bar should fail
                b.Should().BeFalse();
                info.Code.Should().Be(ErrorCodes.OperationNotPermittedWithCapability);
                barFailAwaiter.SetCompleted();
            });
            barChannel.Attach();
            Assert.True(await barFailAwaiter.Task);

            // upgrade bar
            capability = new Capability();
            capability.AddResource("bar").AllowPublish();
            await realtime.Auth.AuthorizeAsync(new TokenParams
            {
                Capability = capability,
                ClientId   = clientId,
            });

            realtime.Connection.State.Should().Be(ConnectionState.Connected);
            var barSuccessAwaiter = new TaskCompletionAwaiter(5000);

            barChannel.Attach((b2, info2) =>
            {
                b2.Should().BeTrue();
                barChannel.Publish("test", "should-succeed", (b, info) =>
                {
                    b.Should().BeTrue();
                    info.Should().BeNull();
                    barSuccessAwaiter.SetCompleted();
                });
            });

            Assert.True(await barSuccessAwaiter.Task);
        }
Esempio n. 30
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();
            }
        }