Esempio n. 1
0
        public async Task InvalidateEverythingTest()
        {
            var users = Services.GetRequiredService <IUserService>();
            // We need at least 1 user to see count invalidation messages
            await users.CreateAsync(new User()
            {
                Id   = int.MaxValue,
                Name = "Chuck Norris",
            }, true);

            var u1 = await users.TryGetAsync(int.MaxValue);

            var c1 = await Computed.CaptureAsync(_ => users.CountAsync());

            users.Invalidate();

            var u2 = await users.TryGetAsync(int.MaxValue);

            u2 !.IsFrozen.Should().BeTrue();
            var c2 = await Computed.CaptureAsync(_ => users.CountAsync());

            u2.Should().NotBeSameAs(u1);
            u2 !.Id.Should().Be(u1 !.Id);
            u2.Name.Should().Be(u1.Name);

            c2.Should().NotBeSameAs(c1);
            c2 !.Value.Should().Be(c1 !.Value);
        }
        private async Task <IComputed <Screenshot> > GetScreenshotComputedAsync()
        {
            var screenshots = Services.GetRequiredService <IScreenshotService>();
            var computed    = await Computed.CaptureAsync(_ => screenshots.GetScreenshotAsync(1280));

            return(computed);
        }
        public async Task Test1()
        {
            var epsilon = TimeSpan.FromSeconds(0.5);

            await using var serving = await WebSocketHost.ServeAsync();

            var client = Services.GetRequiredService <IClientTimeService>();
            var cTime  = await Computed.CaptureAsync(_ => client.GetTimeAsync());

            cTime.Options.AutoInvalidateTime.Should().Be(ComputedOptions.Default.AutoInvalidateTime);
            if (!cTime.IsConsistent())
            {
                cTime = await cTime.UpdateAsync(false);

                cTime.IsConsistent().Should().BeTrue();
            }
            (DateTime.Now - cTime.Value).Should().BeLessThan(epsilon);

            await TestEx.WhenMet(
                () => cTime.IsConsistent().Should().BeFalse(),
                TimeSpan.FromSeconds(5));

            var time = await cTime.UseAsync();

            (DateTime.Now - time).Should().BeLessThan(epsilon);
        }
        public async Task InvalidationAndCachingTest2()
        {
            // TODO: Fix the test so that it starts right after the time invalidation,
            // otherwise it has a tiny chance of failure
            var time = Services.GetRequiredService <ITimeService>();

            var c1 = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1)));

            c1.Should().NotBeNull();
            var c2 = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2)));

            c2.Should().NotBeNull();
            c1.Should().NotBeSameAs(c2);

            var c1a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1)));

            var c2a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2)));

            c1.Should().BeSameAs(c1a);
            c2.Should().BeSameAs(c2a);

            // Wait for time invalidation
            await Task.Delay(500);

            c1a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1)));

            c2a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2)));

            c1.Should().NotBeSameAs(c1a);
            c2.Should().NotBeSameAs(c2a);
        }
        public async Task BasicTest()
        {
            var kvs = Services.GetRequiredService <IKeyValueStore>();
            var c1  = await Computed.CaptureAsync(_ => kvs.TryGetAsync("1"));

            var c2 = await Computed.CaptureAsync(_ => kvs.TryGetAsync("2"));

            var c3 = await Computed.CaptureAsync(_ => kvs.TryGetAsync("3"));

            c1.Value.Should().BeNull();
            c2.Value.Should().BeNull();
            c3.Value.Should().BeNull();

            var commander = Services.Commander();
            var command   = new NestedOperationLoggerTester.SetManyCommand(
                new[] { "1", "2", "3" }, "v");
            await commander.CallAsync(command);

            c1.IsInvalidated().Should().BeTrue();
            c2.IsInvalidated().Should().BeTrue();
            c3.IsInvalidated().Should().BeTrue();
            c1 = await c1.UpdateAsync(false);

            c2 = await c2.UpdateAsync(false);

            c3 = await c3.UpdateAsync(false);

            c1.Value.Should().Be("v3");
            c2.Value.Should().Be("v2");
            c3.Value.Should().Be("v1");
        }
        public async Task AutoRecomputeTest()
        {
            var time = Services.GetRequiredService <ITimeService>();
            var c    = await Computed.CaptureAsync(
                _ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1)));

            var count = 0L;

            using var state = StateFactory.NewLive <DateTime>(
                      o => o.WithZeroUpdateDelay(),
                      async(_, ct) => await c.UseAsync(ct));
            state.Updated += s
                             => Log.LogInformation($"{++count} -> {s.Value:hh:mm:ss:fff}");

            await TestEx.WhenMet(
                () => count.Should().BeGreaterThan(2),
                TimeSpan.FromSeconds(5));

            var lastCount = count;

            state.Dispose();

            await Task.Delay(1000);

            count.Should().Be(lastCount);
        }
        public async Task BasicTest()
        {
            var services    = CreateServiceProviderFor <MathService>();
            var math        = services.GetRequiredService <MathService>();
            var allComputed = new HashSet <IComputed>();

            var c1 = await Computed.CaptureAsync(_ => math.SumAsync(null));

            c1.Value.Should().Be(0);
            allComputed.Add(c1);
            var c2 = await Computed.CaptureAsync(_ => math.SumAsync(null));

            c2.Should().BeSameAs(c1);

            for (var i = 0; i < 20; i++)
            {
                var values = Enumerable.Range(0, i).ToArray();
                c1 = await Computed.CaptureAsync(_ => math.SumAsync(values));

                c1.Value.Should().Be(values.Sum());
                allComputed.Add(c1);
                c2 = await Computed.CaptureAsync(_ => math.SumAsync(values));

                c2.Should().BeSameAs(c1);
            }

            allComputed.Count.Should().Be(21);
        }
Esempio n. 8
0
        public static async Task <IPublication <T> > PublishAsync <T>(
            this IPublisher publisher,
            Func <CancellationToken, Task <T> > producer,
            CancellationToken cancellationToken = default)
        {
            var computed = await Computed
                           .CaptureAsync(producer, cancellationToken)
                           .ConfigureAwait(false);

            var publication = (IPublication <T>)publisher.Publish(computed);

            // Publication doesn't have to be "in sync" with the computed
            // we requested it for (i.e. it might still point to its older,
            // inconsistent version), so we have to update it here.
            try {
                await publication.UpdateAsync(cancellationToken);
            }
            catch (OperationCanceledException) {
                throw;
            }
            catch {
                // Intended
            }
            return(publication);
        }
Esempio n. 9
0
        public static async Task UseCalculator5()
        {
            #region part04_useCalculator5
            var calc = Create <Calculator>();

            var s1 = await calc.SumAsync(1, 1);

            WriteLine($"{nameof(s1)} = {s1}");

            // Now let's pull the computed instance that represents the result of
            // Notice that the underlying SumAsync code won't be invoked,
            // since the result is already cached:
            var c1 = await Computed.CaptureAsync(_ => calc.SumAsync(1, 1));

            WriteLine($"{nameof(c1)} = {c1}, Value = {c1.Value}");

            // And invalidate it
            c1.Invalidate();
            WriteLine($"{nameof(c1)} = {c1}, Value = {c1.Value}");

            // Let's compute the sum once more now.
            // You'll see that SumAsync gets invoked this time.
            s1 = await calc.SumAsync(1, 1);

            WriteLine($"{nameof(s1)} = {s1}");
            #endregion
        }
Esempio n. 10
0
        public async Task BasicTest()
        {
            var liveClock = Services.GetRequiredService <ILiveClock>();

            var cTime = await Computed.CaptureAsync(_ => liveClock.GetUtcNowAsync());

            cTime.IsConsistent().Should().BeTrue();
            (DateTime.UtcNow - cTime.Value).Should().BeLessThan(TimeSpan.FromSeconds(1.1));
            await DelayAsync(1.3);

            cTime.IsConsistent().Should().BeFalse();

            cTime = await Computed.CaptureAsync(_ => liveClock.GetUtcNowAsync(TimeSpan.FromMilliseconds(200)));

            cTime.IsConsistent().Should().BeTrue();
            await DelayAsync(0.25);

            cTime.IsConsistent().Should().BeFalse();

            var now = DateTime.UtcNow;
            var ago = await liveClock.GetMomentsAgoAsync(now);

            ago.Should().Be("just now");
            await DelayAsync(1.8);

            ago = await liveClock.GetMomentsAgoAsync(now);

            ago.Should().Be("1 second ago");
        }
Esempio n. 11
0
        public static async Task IncrementCounter()
        {
            #region Part02_IncrementCounter
            var counters = CreateServices().GetRequiredService <CounterService>();

            Task.Run(async() => {
                for (var i = 0; i <= 5; i++)
                {
                    await Task.Delay(1000);
                    counters.Increment("a");
                }
            }).Ignore();

            var computed = await Computed.CaptureAsync(_ => counters.GetAsync("a"));

            WriteLine($"{DateTime.Now}: {computed.Value}");
            for (var i = 0; i < 5; i++)
            {
                await computed.WhenInvalidatedAsync();

                computed = await computed.UpdateAsync(false);

                WriteLine($"{DateTime.Now}: {computed.Value}");
            }
            #endregion
        }
Esempio n. 12
0
        public async Task KeepAliveTimeTest()
        {
            var users = Services.GetRequiredService <IUserService>();

            var cUser0 = await Computed.CaptureAsync(_ => users.TryGetAsync(0));

            var cCount = await Computed.CaptureAsync(_ => users.CountAsync());

            cUser0 !.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(1));
            cCount !.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(1));
        }
Esempio n. 13
0
        public static async Task CaptureComputed()
        {
            #region Part02_CaptureComputed
            var counters = CreateServices().GetRequiredService <CounterService>();
            var computed = await Computed.CaptureAsync(_ => counters.GetAsync("a"));

            WriteLine($"Computed: {computed}");
            WriteLine($"- IsConsistent(): {computed.IsConsistent()}");
            WriteLine($"- Value:          {computed.Value}");
            #endregion
        }
Esempio n. 14
0
        public static Task <IComputed <T> > MaybePublishAsync <T>(
            this HttpContext httpContext, IPublisher publisher,
            Func <CancellationToken, Task <T> > producer,
            CancellationToken cancellationToken = default)
        {
            var headers     = httpContext.Request.Headers;
            var mustPublish = headers.TryGetValue(FusionHeaders.RequestPublication, out var _);

            return(mustPublish
                ? httpContext.PublishAsync(publisher, producer, cancellationToken)
                : Computed.CaptureAsync(producer, cancellationToken));
        }
        public async Task ExceptionCaptureTest()
        {
            var p = Services.GetRequiredService <ISimplestProvider>();

            p.SetValue(null !); // Will cause an exception in GetCharCountAsync
            var c1 = await Computed.TryCaptureAsync(_ => p.GetCharCountAsync());

            var c2 = await Computed.CaptureAsync(_ => p.GetCharCountAsync());

            c1 !.Error !.GetType().Should().Be(typeof(NullReferenceException));
            c2.Should().BeSameAs(c1);
        }
Esempio n. 16
0
        public static async Task Caching4()
        {
            #region Part05_Caching4
            var service  = CreateServices().GetRequiredService <Service2>();
            var computed = await Computed.CaptureAsync(_ => service.GetAsync("a"));

            WriteLine("computed = GetAsync(a) completed");
            WriteLine(await service.CombineAsync("a", "b"));
            GC.Collect();
            WriteLine("GC.Collect() completed");
            WriteLine(await service.CombineAsync("a", "b"));
            #endregion
        }
Esempio n. 17
0
        public static async Task Caching2()
        {
            #region Part05_Caching2
            var service  = CreateServices().GetRequiredService <Service1>();
            var computed = await Computed.CaptureAsync(_ => service.GetAsync("a"));

            WriteLine(await service.GetAsync("a"));
            WriteLine(await service.GetAsync("a"));
            GC.Collect();
            WriteLine("GC.Collect()");
            WriteLine(await service.GetAsync("a"));
            WriteLine(await service.GetAsync("a"));
            #endregion
        }
Esempio n. 18
0
        public static async Task InvalidateComputed2()
        {
            #region Part02_InvalidateComputed2
            var counters = CreateServices().GetRequiredService <CounterService>();
            var computed = await Computed.CaptureAsync(_ => counters.GetAsync("a"));

            WriteLine($"computed: {computed}");
            WriteLine("Computed.Invalidate(() => counters.GetAsync(\"a\"))");
            Computed.Invalidate(() => counters.GetAsync("a"));                          // <- This line
            WriteLine($"computed: {computed}");
            var newComputed = await Computed.CaptureAsync(_ => counters.GetAsync("a")); // <- This line

            WriteLine($"newComputed: {newComputed}");
            #endregion
        }
Esempio n. 19
0
        public static async Task InvalidateComputed1()
        {
            #region Part02_InvalidateComputed1
            var counters = CreateServices().GetRequiredService <CounterService>();
            var computed = await Computed.CaptureAsync(_ => counters.GetAsync("a"));

            WriteLine($"computed: {computed}");
            WriteLine("computed.Invalidate()");
            computed.Invalidate();
            WriteLine($"computed: {computed}");
            var newComputed = await computed.UpdateAsync(false);

            WriteLine($"newComputed: {newComputed}");
            #endregion
        }
        public async Task InvalidationAndCachingTest1()
        {
            var time = Services.GetRequiredService <ITimeService>();

            var c1 = await Computed.CaptureAsync(_ => time.GetTimeAsync());

            // Wait for time invalidation
            await Task.Delay(500);

            var c2a = await Computed.CaptureAsync(_ => time.GetTimeAsync());

            c2a.Should().NotBeSameAs(c1);
            var c2b = await Computed.CaptureAsync(_ => time.GetTimeAsync());

            c2b.Should().BeSameAs(c2a);
        }
Esempio n. 21
0
        public async Task BasicTest()
        {
            if (OSInfo.Kind == OSKind.Unix)
            {
                // Screenshots don't work on Unix
                return;
            }

            var screenshots = Services.GetRequiredService <IScreenshotService>();
            var c           = await Computed.CaptureAsync(_ => screenshots.GetScreenshotAsync(128));

            c.IsConsistent.Should().BeTrue();
            c.Value.Length.Should().BeGreaterThan(0);
            await Task.Delay(200);

            c.IsConsistent.Should().BeFalse();
        }
        public async Task Test1()
        {
            var epsilon = TimeSpan.FromSeconds(0.5);

            await using var serving = await WebSocketHost.ServeAsync();

            var client = Services.GetRequiredService <IClientTimeService>();
            var cTime  = await Computed.CaptureAsync(_ => client.GetTimeAsync());

            cTime.IsConsistent.Should().BeTrue();
            (DateTime.Now - cTime.Value).Should().BeLessThan(epsilon);

            await Task.Delay(TimeSpan.FromSeconds(2));

            cTime.IsConsistent.Should().BeFalse();
            var time = await cTime.UseAsync();

            (DateTime.Now - time).Should().BeLessThan(epsilon);
        }
        public async Task OptionsTest()
        {
            var d = ComputedOptions.Default;
            var p = Services.GetRequiredService <ISimplestProvider>();

            p.SetValue("");

            var c1 = await Computed.CaptureAsync(_ => p.GetValueAsync());

            c1.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(10));
            c1.Options.ErrorAutoInvalidateTime.Should().Be(d.ErrorAutoInvalidateTime);
            c1.Options.AutoInvalidateTime.Should().Be(d.AutoInvalidateTime);

            var c2 = await Computed.CaptureAsync(_ => p.GetCharCountAsync());

            c2.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(0.5));
            c2.Options.ErrorAutoInvalidateTime.Should().Be(TimeSpan.FromSeconds(0.5));
            c2.Options.AutoInvalidateTime.Should().Be(d.AutoInvalidateTime);
        }
Esempio n. 24
0
        static async Task Main(string[] args)
        {
            var services = new ServiceCollection()
                           .AddFusion()
                           .AddComputeService <UserService>()
                           .AddComputeService <GreetingService>()
                           .BackToServices()
                           .BuildServiceProvider();

            var users     = services.GetRequiredService <UserService>();
            var greetings = services.GetRequiredService <GreetingService>();
            var userId    = 1;
            var user      = new User(userId, "(name isn't set yet)");
            await users.AddOrUpdateUserAsync(user);

            Task.Run(async() => {
                var computed = await Computed.CaptureAsync(_ => greetings.GreetUserAsync(userId));
                while (true)
                {
                    Console.WriteLine($"Background task: {computed.Value}");
                    // Wait for invalidation of GreetUserAsync(userId) result (IComputed);
                    // The invalidation is triggered by the following chain:
                    // AddOrUpdateUserAsync -> GetUserAsync -> GreetUserAsync.
                    await computed.WhenInvalidatedAsync();
                    // Computed instances are immutable, so we need
                    // to get a new one to observe the updated value.
                    computed = await computed.UpdateAsync(false);
                }
            }).Ignore();

            // Notice the code below doesn't even know there are some IComputed, etc.
            while (true)
            {
                Console.WriteLine("What's your name?");
                var name = Console.ReadLine() ?? "";
                await users.AddOrUpdateUserAsync(new User(userId, name));

                var greeting = await greetings.GreetUserAsync(userId);

                Console.WriteLine(greeting);
            }
        }
        public async Task CounterServiceTest()
        {
            using var stopCts = new CancellationTokenSource();
            var cancellationToken = stopCts.Token;

            async Task WatchAsync <T>(string name, IComputed <T> computed)
            {
                for (;;)
                {
                    Out.WriteLine($"{name}: {computed.Value}, {computed}");
                    await computed.WhenInvalidatedAsync(cancellationToken);

                    Out.WriteLine($"{name}: {computed.Value}, {computed}");
                    computed = await computed.UpdateAsync(false, cancellationToken);
                }
            }

            var services  = CreateServiceProviderFor <CounterService>();
            var counters  = services.GetService <CounterService>();
            var aComputed = await Computed.CaptureAsync(_ => counters.GetAsync("a"));

            Task.Run(() => WatchAsync(nameof(aComputed), aComputed)).Ignore();
            var bComputed = await Computed.CaptureAsync(_ => counters.GetAsync("b"));

            Task.Run(() => WatchAsync(nameof(bComputed), bComputed)).Ignore();

            await counters.IncrementAsync("a");

            await counters.SetOffsetAsync(10);

            aComputed = await aComputed.UpdateAsync(false);

            aComputed.Value.Should().Be(11);
            aComputed.IsConsistent().Should().BeTrue();

            bComputed = await bComputed.UpdateAsync(false);

            bComputed.Value.Should().Be(10);
            bComputed.IsConsistent().Should().BeTrue();

            stopCts.Cancel();
        }
Esempio n. 26
0
        public async Task BasicTest()
        {
            var services = CreateServiceProviderFor <CounterService>();
            var counters = services.GetRequiredService <CounterService>();

            var c = Computed.TryGetExisting(() => counters.GetAsync("a"));

            c.Should().BeNull();

            c = await Computed.CaptureAsync(_ => counters.GetAsync("a"));

            c.Value.Should().Be(0);
            var c1 = Computed.TryGetExisting(() => counters.GetAsync("a"));

            c1.Should().BeSameAs(c);

            await counters.IncrementAsync("a");

            c.IsConsistent().Should().BeFalse();
            c1 = Computed.TryGetExisting(() => counters.GetAsync("a"));
            c1.Should().BeNull();
        }
Esempio n. 27
0
        public static async Task UseServices_Part2()
        {
            #region part05_useServices_part2
            var services  = CreateServiceProvider();
            var users     = services.GetRequiredService <UserRegistry>();
            var formatter = services.GetRequiredService <FormatService>();

            users.SetUserName(0, "John Carmack");
            var cFormattedUser0 = await Computed.CaptureAsync(async _ =>
                                                              await formatter.FormatUserNameAsync(0));

            for (var i = 0; i < 10; i++)
            {
                WriteLine(cFormattedUser0.Value);
                await cFormattedUser0.WhenInvalidatedAsync();

                // Note that nothing gets recomputed automatically;
                // on a positive side, any IComputed knows how to recompute itself,
                // so you can always do this manually:
                cFormattedUser0 = await cFormattedUser0.UpdateAsync(false);
            }
            #endregion
        }
Esempio n. 28
0
        public async Task AutoRecomputeTest()
        {
            var time = Services.GetRequiredService <ITimeService>();
            var c    = await Computed.CaptureAsync(
                _ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1)));

            var count = 0L;

            void OnInvalidated(IComputed <DateTime> @new, Result <DateTime> old, Exception?updateError)
            => Log.LogInformation($"{++count} -> {@new.Value:hh:mm:ss:fff}");

            using (var _ = c !.AutoUpdate(OnInvalidated)) {
                await Task.Delay(3000);
            }
            var lastCount = count;

            Out.WriteLine("Completed AutoRecompute.");

            await Task.Delay(1000);

            count.Should().Be(lastCount);
            count.Should().BeGreaterThan(3);
        }
Esempio n. 29
0
        public async Task BasicTest()
        {
            using var stopCts = new CancellationTokenSource();
            var cancellationToken = stopCts.Token;

            async Task WatchAsync <T>(string name, IComputed <T> computed)
            {
                for (;;)
                {
                    Out.WriteLine($"{name}: {computed.Value}, {computed}");
                    await computed.WhenInvalidatedAsync(cancellationToken);

                    Out.WriteLine($"{name}: {computed.Value}, {computed}");
                    computed = await computed.UpdateAsync(false, cancellationToken);
                }
            }

            var services       = CreateServiceProviderFor <PerUserCounterService>();
            var counters       = services.GetRequiredService <PerUserCounterService>();
            var sessionFactory = services.GetRequiredService <ISessionFactory>();
            var sessionA       = sessionFactory.CreateSession();
            var sessionB       = sessionFactory.CreateSession();

            var session    = sessionA;
            var aaComputed = await Computed.CaptureAsync(_ => counters.GetAsync("a", session));

            Task.Run(() => WatchAsync(nameof(aaComputed), aaComputed)).Ignore();
            var abComputed = await Computed.CaptureAsync(_ => counters.GetAsync("b", session));

            Task.Run(() => WatchAsync(nameof(abComputed), abComputed)).Ignore();

            session = sessionB;
            var baComputed = await Computed.CaptureAsync(_ => counters.GetAsync("a", session));

            Task.Run(() => WatchAsync(nameof(baComputed), baComputed)).Ignore();

            session = sessionA;
            await counters.IncrementAsync("a", session);

            (await aaComputed.UpdateAsync(false)).Value.Should().Be(1);
            (await abComputed.UpdateAsync(false)).Value.Should().Be(0);
            (await baComputed.UpdateAsync(false)).Value.Should().Be(0);
            await counters.IncrementAsync("b", session);

            (await aaComputed.UpdateAsync(false)).Value.Should().Be(1);
            (await abComputed.UpdateAsync(false)).Value.Should().Be(1);
            (await baComputed.UpdateAsync(false)).Value.Should().Be(0);

            session = sessionB;
            await counters.IncrementAsync("a", session);

            (await aaComputed.UpdateAsync(false)).Value.Should().Be(1);
            (await abComputed.UpdateAsync(false)).Value.Should().Be(1);
            (await baComputed.UpdateAsync(false)).Value.Should().Be(1);
            await counters.IncrementAsync("b", session);

            (await aaComputed.UpdateAsync(false)).Value.Should().Be(1);
            (await abComputed.UpdateAsync(false)).Value.Should().Be(1);
            (await baComputed.UpdateAsync(false)).Value.Should().Be(1);

            stopCts.Cancel();
        }
        private async Task ActualTest(IEdgeCaseService service)
        {
            var error = (Exception?)null;
            await service.SetSuffixAsync("");

            (await service.GetSuffixAsync()).Should().Be("");

            // ThrowIfContainsErrorAsync method test
            var c1 = await Computed.CaptureAsync(
                ct => service.ThrowIfContainsErrorAsync("a", ct));

            c1.Value.Should().Be("a");

            var c2 = await Computed.CaptureAsync(
                ct => service.ThrowIfContainsErrorAsync("error", ct));

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorExceptionType);
            c2.Error.Message.Should().Be("!");

            await service.SetSuffixAsync("z");

            c1 = await UpdateAsync(c1);

            c1.Value.Should().Be("az");

            c2 = await UpdateAsync(c2);

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorExceptionType);
            c2.Error.Message.Should().Be("!");
            await service.SetSuffixAsync("");

            // ThrowIfContainsErrorRewriteErrorsAsync method test
            c1 = await Computed.CaptureAsync(
                ct => service.ThrowIfContainsErrorRewriteErrorsAsync("a", ct));

            c1.Value.Should().Be("a");

            c2 = await Computed.CaptureAsync(
                ct => service.ThrowIfContainsErrorRewriteErrorsAsync("error", ct));

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorRewriteErrorsExceptionType);
            c2.Error.Message.Should().Be("!");

            await service.SetSuffixAsync("z");

            c1 = await UpdateAsync(c1);

            c1.Value.Should().Be("az");

            c2 = await UpdateAsync(c2);

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorRewriteErrorsExceptionType);
            c2.Error.Message.Should().Be("!");
            await service.SetSuffixAsync("");

            // ThrowIfContainsErrorRewriteErrorsAsync method test
            (await service.ThrowIfContainsErrorNonComputeAsync("a")).Should().Be("a");
            try {
                await service.ThrowIfContainsErrorNonComputeAsync("error");
            } catch (Exception e) { error = e; }
            error !.GetType().Should().Be(ThrowIfContainsErrorNonComputeExceptionType);
            error.Message.Should().Be("!");

            await service.SetSuffixAsync("z");

            (await service.ThrowIfContainsErrorNonComputeAsync("a")).Should().Be("az");
            try {
                await service.ThrowIfContainsErrorNonComputeAsync("error");
            } catch (Exception e) { error = e; }
            error !.GetType().Should().Be(ThrowIfContainsErrorNonComputeExceptionType);
            error.Message.Should().Be("!");
            await service.SetSuffixAsync("");
        }