Exemple #1
0
    public async Task TimerTest()
    {
        await using var serving = await WebHost.Serve();

        var publisher  = WebServices.GetRequiredService <IPublisher>();
        var replicator = ClientServices.GetRequiredService <IReplicator>();
        var tp         = WebServices.GetRequiredService <ITimeService>();

        var pub = await publisher.Publish(_ => tp.GetTime());

        var rep = replicator.GetOrAdd <DateTime>(pub.Ref);
        await rep.RequestUpdate().AsAsyncFunc()
        .Should().CompleteWithinAsync(TimeSpan.FromMinutes(1));

        var count = 0;

        using var state = WebServices.StateFactory().NewComputed <DateTime>(
                  UpdateDelayer.ZeroDelay,
                  async(_, ct) => await rep.Computed.Use(ct));
        state.Updated += (s, _) => {
            Out.WriteLine($"Client: {s.Value}");
            count++;
        };

        await TestExt.WhenMet(
            () => count.Should().BeGreaterThan(2),
            TimeSpan.FromSeconds(5));
    }
        public async Task TimerTest()
        {
            await using var serving = await WebHost.Serve();

            var publisher  = WebServices.GetRequiredService <IPublisher>();
            var replicator = ClientServices.GetRequiredService <IReplicator>();
            var tp         = WebServices.GetRequiredService <ITimeService>();

            var pub = await publisher.Publish(_ => tp.GetTime());

            var rep = replicator.GetOrAdd <DateTime>(pub.Ref);

            var count = 0;

            using var state = Services.StateFactory().NewLive <DateTime>(
                      o => o.WithInstantUpdates(),
                      async(_, ct) => await rep.Computed.Use(ct));
            state.Updated += (s, _) => {
                Out.WriteLine($"{s.Value}");
                count++;
            };

            await TestEx.WhenMet(
                () => count.Should().BeGreaterThan(2),
                TimeSpan.FromSeconds(5));
        }
Exemple #3
0
    public async Task NoConnectionTest()
    {
        await using var serving = await WebHost.Serve();

        var publisher  = WebServices.GetRequiredService <IPublisher>();
        var replicator = ClientServices.GetRequiredService <IReplicator>();
        var time       = WebServices.GetRequiredService <ITimeService>();

        var pub = await publisher.Publish(_ => time.GetTime());

        var rep1 = replicator.GetOrAdd <DateTime>(("NoPublisher", pub.Id));

        rep1.Computed.IsConsistent().Should().BeFalse();
        var updateTask1 = rep1.RequestUpdate();

        var psi2 = new PublicationStateInfo <DateTime>(
            ("NoPublisher1", pub.Id),
            new LTag(123),
            true,
            pub.State.Computed.Value);
        var rep2 = replicator.GetOrAdd(psi2);

        rep2.Computed.IsConsistent().Should().BeTrue();
        var updateTask2 = rep2.RequestUpdate();

        await Delay(30);

        // No publisher = no update
        updateTask1.IsCompleted.Should().BeFalse();
        updateTask2.IsCompleted.Should().BeFalse();
        // And state should be the same (shouldn't reset to inconsistent)
        rep1.Computed.IsConsistent().Should().BeFalse();
        rep2.Computed.IsConsistent().Should().BeTrue();
    }
Exemple #4
0
    public async Task BasicTest()
    {
        if (OSInfo.IsAnyUnix)
        {
            // Screenshots don't work on Unix
            return;
        }

#if NETCOREAPP
        var epsilon = TimeSpan.FromSeconds(0.5);
#else
        var epsilon = TimeSpan.FromSeconds(0.8);
#endif

        await using var serving = await WebHost.Serve();
        await Delay(0.25);

        var service = ClientServices.GetRequiredService <IScreenshotServiceClient>();

        ScreenshotController.CallCount = 0;
        for (var i = 0; i < 50; i++)
        {
            var screenshot = await service.GetScreenshot(100);

            screenshot.Should().NotBeNull();
            (SystemClock.Now - screenshot.CapturedAt).Should().BeLessThan(epsilon);
            await Task.Delay(TimeSpan.FromSeconds(0.02));
        }
        ScreenshotController.CallCount.Should().BeLessThan(15);
    }
        public async Task TestRewriteClient()
        {
            await using var serving = await WebHost.Serve();

            var client  = ClientServices.GetRequiredService <IEdgeCaseRewriteClient>();
            var tfv     = ClientServices.GetTypeViewFactory <IEdgeCaseService>();
            var service = tfv.CreateView(client);

            // ReSharper disable once SuspiciousTypeConversion.Global
            (service is TypeView <IEdgeCaseService>).Should().BeTrue();
            // ReSharper disable once SuspiciousTypeConversion.Global
            (service is TypeView <IEdgeCaseRewriteClient, IEdgeCaseService>).Should().BeTrue();

            // This part tests that proxy builder generates
            // a different type for each combination of <TView, TImplementation>
            var otherClient  = ClientServices.GetRequiredService <IEdgeCaseClient>();
            var otherService = tfv.CreateView(otherClient);

            service.GetType().Should().NotBeSameAs(otherService.GetType());

            ThrowIfContainsErrorExceptionType              = typeof(ServiceException);
            ThrowIfContainsErrorNonComputeExceptionType    = typeof(ServiceException);
            ThrowIfContainsErrorRewriteErrorsExceptionType = typeof(ServiceException);

            await ActualTest(service);
        }
        public async Task CommandTest()
        {
            await using var _ = await WebHost.Serve();

            // Server commands
            var kv = WebServices.GetRequiredService <IKeyValueService <string> >();

            (await kv.Get("")).Should().BeNull();

            await kv.SetCmd(new IKeyValueService <string> .SetCommand("", "1"));

            (await kv.Get("")).Should().Be("1");

            await WebServices.Commander().Call(new IKeyValueService <string> .SetCommand("", "2"));

            (await kv.Get("")).Should().Be("2");

            // Client commands
            var kvc = ClientServices.GetRequiredService <IKeyValueServiceClient <string> >();

            (await kv.Get("")).Should().Be("2");

            await kvc.SetCmd(new IKeyValueService <string> .SetCommand("", "1"));

            await Task.Delay(100); // Remote invalidation takes some time

            (await kvc.Get("")).Should().Be("1");

            await ClientServices.Commander().Call(new IKeyValueService <string> .SetCommand("", "2"));

            await Task.Delay(100); // Remote invalidation takes some time

            (await kvc.Get("")).Should().Be("2");
        }
        public async Task ConnectToPublisherTest()
        {
            await using var serving = await WebHost.Serve();

            var channel = await ConnectToPublisher();

            channel.Writer.Complete();
        }
Exemple #8
0
        public async Task Test1()
        {
            var epsilon = TimeSpan.FromSeconds(0.5);

            await using var serving = await WebHost.Serve();

            var client = ClientServices.GetRequiredService <IClientTimeService>();
            var cTime  = await Computed.Capture(_ => client.GetTime(default));
Exemple #9
0
        public async Task GetFromPath()
        {
            await using var serving = await WebHost.Serve();

            var service = ClientServices.GetRequiredService <IRestEaseClient>();

            (await service.GetFromPath("abcD")).Should().Be("abcD");
        }
Exemple #10
0
        public async Task PostWithBody()
        {
            await using var serving = await WebHost.Serve();

            var service = ClientServices.GetRequiredService <IRestEaseClient>();

            var jsonString = await service.PostWithBody(new StringWrapper("abcD"));

            jsonString.Value.Should().Be("abcD");
        }
Exemple #11
0
        public async Task PostFromPath()
        {
            await using var serving = await WebHost.Serve();

            var service = ClientServices.GetRequiredService <IRestEaseClient>();

            var jsonString = (await service.PostFromPath("abcD"));

            jsonString.Value.Should().Be("abcD");
        }
Exemple #12
0
    public async Task ServerTimeModelTest1()
    {
        await using var serving = await WebHost.Serve();

        using var stm = ClientServices.GetRequiredService <IComputedState <ServerTimeModel1> >();

        var c = stm.Computed;

        c.IsConsistent().Should().BeFalse();
        c.Value.Time.Should().Be(default);
        public async Task TestClient()
        {
            await using var serving = await WebHost.Serve();

            var client  = ClientServices.GetRequiredService <IEdgeCaseClient>();
            var tfv     = ClientServices.GetTypeViewFactory <IEdgeCaseService>();
            var service = tfv.CreateView(client);

            await ActualTest(service);
        }
Exemple #14
0
        public async Task ConcatPathAndBody()
        {
            await using var serving = await WebHost.Serve();

            var service = ClientServices.GetRequiredService <IRestEaseClient>();

            var jsonString = (await service.ConcatPathAndBody("ab", "cD"));

            jsonString.Value.Should().Be("abcD");
        }
        public async Task ContainerConfigTest()
        {
            await using var serving = await WebHost.Serve();

            var agentInfo1 = WebServices.GetRequiredService <AgentInfo>();
            var agentInfo2 = Services.GetRequiredService <AgentInfo>();
            var notifier1  = WebServices.GetRequiredService <IOperationCompletionNotifier>();
            var notifier2  = Services.GetRequiredService <IOperationCompletionNotifier>();

            agentInfo1.Should().NotBe(agentInfo2);
            agentInfo1.Id.Should().NotBe(agentInfo2.Id);
            notifier1.Should().NotBe(notifier2);
        }
Exemple #16
0
        public async Task BasicTest()
        {
            await using var _ = await WebHost.Serve();

            var kv = WebServices.GetRequiredService <IKeyValueService <string> >();

            (await kv.TryGet("")).Should().Be(Option.None <string>());
            (await kv.Get("")).Should().BeNull();
            await kv.Set("", "1");

            (await kv.TryGet("")).Should().Be(Option.Some("1"));
            (await kv.Get("")).Should().Be("1");

            using var kvm = ClientServices.GetRequiredService <IComputedState <KeyValueModel <string> > >();
            var kvc = ClientServices.GetRequiredService <IKeyValueServiceClient <string> >();

            // First read
            var c = kvm.Computed;

            c.IsConsistent().Should().BeFalse();
            c.Value.Key.Should().Be("");
            c.Value.Value.Should().BeNull();
            c.Value.UpdateCount.Should().Be(0);

            await TestEx.WhenMet(() => {
                var snapshot = kvm.Snapshot;
                snapshot.Computed.HasValue.Should().BeTrue();
                var c = snapshot.Computed;
                c.IsConsistent().Should().BeTrue();
                c.Value.Key.Should().Be("");
                c.Value.Value.Should().Be("1");
                c.Value.UpdateCount.Should().Be(1);
            }, TimeSpan.FromSeconds(1));

            // Update
            await kvc.Set(kvm.Computed.Value.Key, "2");

            await Task.Delay(300);

            c = kvm.Computed;
            c.IsConsistent().Should().BeFalse();
            c.Value.Value.Should().Be("1");
            c.Value.UpdateCount.Should().Be(1);

            await Task.Delay(1000);

            c = kvm.Computed;
            c.IsConsistent().Should().BeTrue();
            c.Value.Value.Should().Be("2");
            c.Value.UpdateCount.Should().Be(2);
        }
        public async Task NoConnectionTest()
        {
            await using var serving = await WebHost.Serve();

            var publisher  = WebServices.GetRequiredService <IPublisher>();
            var replicator = ClientServices.GetRequiredService <IReplicator>();
            var tp         = WebServices.GetRequiredService <ITimeService>();

            var pub = await publisher.Publish(_ => tp.GetTime());

            var rep = replicator.GetOrAdd <DateTime>(("NoPublisher", pub.Id));
            await rep.RequestUpdate().AsAsyncFunc()
            .Should().ThrowAsync <WebSocketException>();
        }
Exemple #18
0
        public async Task MultiHostInvalidationTest()
        {
            var users = Services.GetRequiredService <IUserService>();

            await using var _ = await WebHost.Serve();

            var webUsers = WebServices.GetRequiredService <IUserService>();

            async Task PingPong(IUserService users1, IUserService users2, User user)
            {
                var count0 = await users1.Count();

                (await users2.Count()).Should().Be(count0);

                await users1.Create(new(user));

                (await users1.Count()).Should().Be(++count0);

                await Delay(0.5);

                var user2 = await users2.TryGet(user.Id);

                user2.Should().NotBeNull();
                user2 !.Id.Should().Be(user.Id);
                (await users2.Count()).Should().Be(count0);
            }

            for (var i = 0; i < 5; i++)
            {
                var id1 = i * 2;
                var id2 = id1 + 1;
                Out.WriteLine($"{i}: ping...");
                await PingPong(users, webUsers, new User()
                {
                    Id = id1, Name = id1.ToString()
                });

                Out.WriteLine($"{i}: pong...");
                await PingPong(users, webUsers, new User()
                {
                    Id = id2, Name = id2.ToString()
                });

                // await PingPong(webUsers, users, new User() { Id = id2, Name = id2.ToString()});
            }
        }
Exemple #19
0
        public async Task ExceptionTest()
        {
            await using var _ = await WebHost.Serve();

            var kv = WebServices.GetRequiredService <IKeyValueService <string> >();

            try {
                await kv.Get("error");
            }
            catch (ApplicationException ae) {
                ae.Message.Should().Be("Error!");
            }

            var kvc = ClientServices.GetRequiredService <IKeyValueServiceClient <string> >();

            try {
                await kvc.Get("error");
            }
            catch (ApplicationException ae) {
                ae.Message.Should().Be("Error!");
            }
        }
        public async Task BasicTest()
        {
            await using var serving = await WebHost.Serve();

            var publisher  = WebServices.GetRequiredService <IPublisher>();
            var replicator = ClientServices.GetRequiredService <IReplicator>();

            using var scope = WebServices.CreateScope();
            var sp = scope.ServiceProvider.GetRequiredService <ISimplestProvider>();

            sp.SetValue("");
            var p1 = await publisher.Publish(_ => sp.GetValue());

            p1.Should().NotBeNull();

            var r1  = replicator.GetOrAdd <string>(p1.Ref, true);
            var r1c = await r1.Computed.Update();

            r1c.IsConsistent().Should().BeTrue();
            r1c.Value.Should().Be("");
            r1.Computed.Should().Be(r1c);

            sp.SetValue("1");
            await Task.Delay(100);

            r1c.IsConsistent().Should().BeFalse();
            r1.Computed.Should().Be(r1c);

            r1c = await r1c.Update();

            r1c.Value.Should().Be("1");

            var r1c1 = await r1c.Update();

            r1c1.Should().Be(r1c);
        }
Exemple #21
0
        public async Task BasicTest()
        {
            if (OSInfo.IsAnyUnix)
            {
                // Screenshots don't work on Unix
                return;
            }

            var epsilon = TimeSpan.FromSeconds(0.5);

            await using var serving = await WebHost.Serve();

            var service = ClientServices.GetRequiredService <IScreenshotServiceClient>();

            ScreenshotController.CallCount = 0;
            for (int i = 0; i < 20; i++)
            {
                var screenshot = await service.GetScreenshot(100);

                (DateTime.Now - screenshot.CapturedAt).Should().BeLessThan(epsilon);
                await Task.Delay(TimeSpan.FromSeconds(0.1));
            }
            ScreenshotController.CallCount.Should().BeLessThan(10);
        }
Exemple #22
0
    public async Task DropReconnectTest()
    {
        if (TestRunnerInfo.IsBuildAgent())
        {
            // TODO: Fix intermittent failures on GitHub
            return;
        }

        var serving = await WebHost.Serve(false);

        var replicator = ClientServices.GetRequiredService <IReplicator>();
        var kvsClient  = ClientServices.GetRequiredService <IKeyValueServiceClient <string> >();

        Debug.WriteLine("0");
        var kvs = WebServices.GetRequiredService <IKeyValueService <string> >();
        await kvs.Set("a", "b");

        var c = (ReplicaMethodComputed <string>)
                await Computed.Capture(_ => kvsClient.Get("a"));

        c.Value.Should().Be("b");
        c.IsConsistent().Should().BeTrue();

        Debug.WriteLine("1");
        await c.Replica !.RequestUpdate().AsAsyncFunc()
        .Should().CompleteWithinAsync(TimeSpan.FromSeconds(5));

        c.IsConsistent().Should().BeTrue();

        Debug.WriteLine("2");
        var cs = replicator.GetPublisherConnectionState(c.Replica.PublicationRef.PublisherId);

        cs.Value.Should().BeTrue();
        cs.Computed.IsConsistent().Should().BeTrue();
        await cs.Recompute();

        Debug.WriteLine("3");
        cs.Value.Should().BeTrue();
        cs.Computed.IsConsistent().Should().BeTrue();
        var cs1 = replicator.GetPublisherConnectionState(c.Replica.PublicationRef.PublisherId);

        cs1.Should().BeSameAs(cs);

        Debug.WriteLine("WebServer: stopping.");
        await serving.DisposeAsync();

        Debug.WriteLine("WebServer: stopped.");

        // First try -- should fail w/ WebSocketException or ChannelClosedException
        c.IsConsistent().Should().BeTrue();
        c.Value.Should().Be("b");
        Debug.WriteLine("4");

        await cs.Update();

        cs.Error.Should().BeAssignableTo <Exception>();
        cs.Computed.IsConsistent().Should().BeTrue();
        var updateTask = c.Replica.RequestUpdate();

        updateTask.IsCompleted.Should().BeFalse();
        Debug.WriteLine("5");

        await kvs.Set("a", "c");

        await Delay(0.1);

        c.IsConsistent().Should().BeTrue();
        c.Value.Should().Be("b");
        Debug.WriteLine("6");

        Debug.WriteLine("WebServer: starting.");
        serving = await WebHost.Serve();
        await Delay(1);

        Debug.WriteLine("WebServer: started.");

        await TestExt.WhenMet(
            () => cs.Error.Should().BeNull(),
            TimeSpan.FromSeconds(30));

        Debug.WriteLine("7");

        await Delay(1);

        updateTask.IsCompleted.Should().BeTrue();
        c = (ReplicaMethodComputed <string>) await c.Update();

        c.IsConsistent().Should().BeTrue();
        c.Value.Should().Be("c");

        await serving.DisposeAsync();
    }
        public async Task BasicTest1()
        {
            await using var serving = await WebHost.Serve();

            var authServer     = WebServices.GetRequiredService <IServerSideAuthService>();
            var authClient     = ClientServices.GetRequiredService <IAuthService>();
            var authLocal      = Services.GetRequiredService <IServerSideAuthService>();
            var sessionFactory = ClientServices.GetRequiredService <ISessionFactory>();
            var sessionA       = sessionFactory.CreateSession();
            var sessionB       = sessionFactory.CreateSession();
            var bob            = new User("", "Bob").WithIdentity("g:1");

            var session = sessionA;
            await WebServices.Commander().Call(
                new SignInCommand(session, bob).MarkServerSide());

            var user = await authServer.GetUser(session);

            user.Name.Should().Be(bob.Name);
            long.TryParse(user.Id, out var _).Should().BeTrue();
            user.Claims.Count.Should().Be(0);
            bob = user;

            // Trying to edit user name
            var newName = "Bobby";
            await authClient.EditUser(new(session, newName));

            user = await authServer.GetUser(session);

            user.Name.Should().Be(newName);
            bob = bob with {
                Name = newName
            };

            // Checking if the client is able to see the same user & sessions
            user = await authClient.GetUser(sessionA);

            user.Id.Should().Be(bob.Id);
            user.IsAuthenticated.Should().BeTrue();
            user = await authClient.GetUser(session);

            user.Id.Should().Be(bob.Id);
            user.IsAuthenticated.Should().BeTrue();

            // Checking if local service is able to see the same user & sessions
            if (!Options.UseInMemoryAuthService)
            {
                await Delay(0.5);

                user = await authLocal.GetUser(session);

                user.Id.Should().Be(bob.Id);
                user.IsAuthenticated.Should().BeTrue();
            }

            // Checking guest session
            session = sessionB;
            user    = await authClient.GetUser(session);

            user.IsAuthenticated.Should().BeFalse();

            // Checking sign-out
            await WebServices.Commander().Call(new SignOutCommand(sessionA));

            user = await authServer.GetUser(sessionA);

            user.IsAuthenticated.Should().BeFalse();
            await Delay(0.5);

            user = await authClient.GetUser(sessionA);

            user.IsAuthenticated.Should().BeFalse();
            if (!Options.UseInMemoryAuthService)
            {
                user = await authLocal.GetUser(sessionA);

                user.IsAuthenticated.Should().BeFalse();
            }
        }
        public async Task BasicTest2()
        {
            await using var serving = await WebHost.Serve();

            var authServer     = WebServices.GetRequiredService <IServerSideAuthService>();
            var authClient     = ClientServices.GetRequiredService <IAuthService>();
            var authLocal      = Services.GetRequiredService <IServerSideAuthService>();
            var sessionFactory = ClientServices.GetRequiredService <ISessionFactory>();
            var sessionA       = sessionFactory.CreateSession();
            var sessionB       = sessionFactory.CreateSession();
            var bob            = new User("", "Bob")
                                 .WithClaim("id", "bob")
                                 .WithIdentity("g:1");

            var session = sessionA;
            await authServer.SignIn(new SignInCommand(session, bob).MarkServerSide());

            var user = await authServer.GetUser(session);

            user.Name.Should().Be(bob.Name);
            long.TryParse(user.Id, out var _).Should().BeTrue();
            user.Claims.Count.Should().Be(1);
            user.Identities.Single(); // Client-side users shouldn't have them

            // Server-side methods to get the same user
            var sameUser = await authServer.TryGetUser(user.Id);

            sameUser !.Id.Should().Be(user.Id);
            sameUser.Name.Should().Be(user.Name);
            sameUser.Identities.Keys.Select(i => i.Id.Value).Should().BeEquivalentTo(new [] { "g:1" });
            bob = user;

            // Checking if the client is able to see the same user & sessions
            user = await authClient.GetUser(sessionA);

            user.Id.Should().Be(bob.Id);
            user.IsAuthenticated.Should().BeTrue();
            user = await authClient.GetUser(session);

            user.Id.Should().Be(bob.Id);
            user.IsAuthenticated.Should().BeTrue();

            // Checking if local service is able to see the same user & sessions
            if (!Options.UseInMemoryAuthService)
            {
                await Delay(0.5);

                user = await authLocal.GetUser(session);

                user.Id.Should().Be(bob.Id);
                user.IsAuthenticated.Should().BeTrue();
            }

            // Checking guest session
            session = sessionB;
            user    = await authClient.GetUser(session);

            user.IsAuthenticated.Should().BeFalse();

            // Checking sign-out
            await authServer.SignOut(new(sessionA));

            user = await authServer.GetUser(sessionA);

            user.IsAuthenticated.Should().BeFalse();
            await Delay(0.5);

            user = await authClient.GetUser(sessionA);

            user.IsAuthenticated.Should().BeFalse();
            if (!Options.UseInMemoryAuthService)
            {
                user = await authLocal.GetUser(sessionA);

                user.IsAuthenticated.Should().BeFalse();
            }
        }
Exemple #25
0
    public async Task CommunicationTest()
    {
        await using var serving = await WebHost.Serve();

        var publisher = WebServices.GetRequiredService <IPublisher>();

        using var wss = WebServices.CreateScope();
        var sp = wss.ServiceProvider.GetRequiredService <ISimplestProvider>();

        var cp = CreateChannelPair("c1");

        publisher.ChannelHub.Attach(cp.Channel1).Should().BeTrue();
        var cReader = cp.Channel2.Reader;

        sp.SetValue("");

        var p1 = await publisher.Publish(_ => sp.GetValue());

        p1.Should().NotBeNull();

        Debug.WriteLine("a1");
        await publisher.Subscribe(cp.Channel1, p1, true);

        Debug.WriteLine("a2");
        var m = await cReader.AssertRead();

        m.Should().BeOfType <PublicationStateReply <string, string> >()
        .Which.Output !.Value.Value.Should().Be("");
        Debug.WriteLine("a3");
        await cReader.AssertCannotRead();

        Debug.WriteLine("b1");
        sp.SetValue("1");
        Debug.WriteLine("b2");
        m = await cReader.AssertRead();

        Debug.WriteLine("b3");
        m.Should().BeOfType <PublicationStateReply <string> >()
        .Which.IsConsistent.Should().BeFalse();
        Debug.WriteLine("b4");
        var pm = (PublicationReply)m;

        pm.PublisherId.Should().Be(publisher.Id);
        pm.PublicationId.Should().Be(p1.Id);
        Debug.WriteLine("b5");
        await cReader.AssertCannotRead();

        Debug.WriteLine("c1");
        sp.SetValue("12");
        // No auto-update after invalidation
        Debug.WriteLine("c2");
        await cReader.AssertCannotRead();

        Debug.WriteLine("d1");
        await publisher.Subscribe(cp.Channel1, p1, true);

        Debug.WriteLine("d2");
        m = await cReader.AssertRead();

        Debug.WriteLine("d3");
        m.Should().BeOfType <PublicationStateReply <string, string> >()
        .Which.IsConsistent.Should().BeTrue();
        m.Should().BeOfType <PublicationStateReply <string, string> >()
        .Which.Output !.Value.Value.Should().Be("12");
        Debug.WriteLine("d4");
        await cReader.AssertCannotRead();

        Debug.WriteLine("e1");
        await p1.DisposeAsync();

        Debug.WriteLine("e2");
        await cReader.AssertCannotRead();

        Debug.WriteLine("f1");
        await publisher.Subscribe(cp.Channel1, p1, true);

        Debug.WriteLine("f2");
        m = await cReader.AssertRead();

        Debug.WriteLine("f3");
        m.Should().BeOfType <PublicationAbsentsReply>();
    }
        public async Task DropReconnectTest()
        {
            if (TestRunnerInfo.IsBuildAgent())
            {
                // TODO: Fix intermittent failures on GitHub
                return;
            }

            var serving = await WebHost.Serve();

            var publisher  = WebServices.GetRequiredService <IPublisher>();
            var replicator = ClientServices.GetRequiredService <IReplicator>();
            var tp         = Services.GetRequiredService <ITimeService>();

            Debug.WriteLine("0");
            var pub = await publisher.Publish(_ => tp.GetTime());

            var rep = replicator.GetOrAdd <DateTime>(pub.Ref);

            Debug.WriteLine("1");
            await rep.RequestUpdate().AsAsyncFunc()
            .Should().CompleteWithinAsync(TimeSpan.FromMinutes(1));

            Debug.WriteLine("2");
            var state = replicator.GetPublisherConnectionState(pub.Publisher.Id);

            state.Computed.IsConsistent().Should().BeTrue();
            Debug.WriteLine("3");
            await state.Computed.Update(false);

            Debug.WriteLine("4");
            state.Should().Be(replicator.GetPublisherConnectionState(pub.Publisher.Id));
            state.Value.Should().BeTrue();

            Debug.WriteLine("WebServer: stopping.");
            await serving.DisposeAsync();

            Debug.WriteLine("WebServer: stopped.");

            // First try -- should fail w/ WebSocketException or ChannelClosedException
            Debug.WriteLine("5");
            await rep.RequestUpdate().AsAsyncFunc()
            .Should().ThrowAsync <Exception>();

            Debug.WriteLine("6");
            state.Should().Be(replicator.GetPublisherConnectionState(pub.Publisher.Id));
            await state.Computed.Update(false);

            Debug.WriteLine("7");
            state.Should().Be(replicator.GetPublisherConnectionState(pub.Publisher.Id));
            state.Error.Should().BeAssignableTo <Exception>();

            // Second try -- should fail w/ WebSocketException
            Debug.WriteLine("8");
            await rep.Computed.Update(false).AsAsyncFunc()
            .Should().ThrowAsync <WebSocketException>();

            Debug.WriteLine("9");
            rep.UpdateError.Should().BeOfType <WebSocketException>();
            await state.Computed.Update(false);

            Debug.WriteLine("10");
            state.Error.Should().BeOfType <WebSocketException>();

            // The remaining part of this test shouldn't work:
            // since the underlying web host is actually re-created on
            // every ServeAsync call, its endpoints change,
            // and moreover, IPublisher, etc. dies there,
            // so reconnect won't happen in this case.
            //
            // TODO: Add similar test relying on Replica Services.

            /*
             * Debug.WriteLine("WebServer: starting.");
             * serving = await WebHost.ServeAsync();
             * await Task.Delay(1000);
             * Debug.WriteLine("WebServer: started.");
             *
             * Debug.WriteLine("11");
             * await rep.RequestUpdateAsync().AsAsyncFunc()
             *  .Should().CompleteWithinAsync(TimeSpan.FromMinutes(1));
             * Debug.WriteLine("12");
             * await state.Computed.UpdateAsync(false);
             * Debug.WriteLine("13");
             * state.Value.Should().BeTrue();
             *
             * Debug.WriteLine("100");
             * await serving.DisposeAsync();
             * Debug.WriteLine("101");
             */
        }