private static AppsIndex[] GetIndexes(bool shouldBreak, GrainEnvironment env, TestCluster cluster)
        {
            return(cluster.Silos.OfType <InProcessSiloHandle>()
                   .Select(x =>
            {
                var pubSub =
                    shouldBreak ?
                    A.Fake <IPubSub>() :
                    x.SiloHost.Services.GetRequiredService <IPubSub>();

                var cache =
                    new ReplicatedCache(
                        new MemoryCache(Options.Create(new MemoryCacheOptions())),
                        pubSub,
                        Options.Create(new ReplicatedCacheOptions {
                    Enable = true
                }));

                return new AppsIndex(env.GrainFactory, cache);
            }).ToArray());
        }
        public async Task Should_distribute_and_cache_domain_objects(short numSilos, int numRuns, int expectedCounts, bool shouldBreak)
        {
            var env = new GrainEnvironment();

            var cluster =
                new TestClusterBuilder(numSilos)
                .AddSiloBuilderConfigurator <Configurator>()
                .Build();

            await cluster.DeployAsync();

            try
            {
                var indexes = GetIndexes(shouldBreak, env, cluster);

                var appId = env.AppId;

                var random = new Random();

                for (var i = 0; i < numRuns; i++)
                {
                    var contributorId      = Guid.NewGuid().ToString();
                    var contributorCommand = new AssignContributor {
                        ContributorId = contributorId, AppId = appId
                    };

                    var commandContext = new CommandContext(contributorCommand, A.Fake <ICommandBus>());

                    var randomIndex = indexes[random.Next(numSilos)];

                    await randomIndex.HandleAsync(commandContext, x =>
                    {
                        if (x.Command is AssignContributor command)
                        {
                            env.HandleCommand(command);
                        }

                        x.Complete(true);

                        return(Task.CompletedTask);
                    });

                    foreach (var index in indexes)
                    {
                        var appById = await index.GetAppAsync(appId.Id, true);

                        var appByName = await index.GetAppByNameAsync(appId.Name, true);

                        if (index == randomIndex || !shouldBreak || i == 0)
                        {
                            Assert.True(appById?.Contributors.ContainsKey(contributorId));
                            Assert.True(appByName?.Contributors.ContainsKey(contributorId));
                        }
                        else
                        {
                            Assert.False(appById?.Contributors.ContainsKey(contributorId));
                            Assert.False(appByName?.Contributors.ContainsKey(contributorId));
                        }
                    }
                }

                env.VerifyGrainAccess(expectedCounts);
            }
            finally
            {
                await Task.WhenAny(Task.Delay(2000), cluster.StopAllSilosAsync());
            }
        }
        public async Task Should_retrieve_new_app(short numSilos, bool shouldBreak)
        {
            var env = new GrainEnvironment();

            var cluster =
                new TestClusterBuilder(numSilos)
                .AddSiloBuilderConfigurator <Configurator>()
                .Build();

            await cluster.DeployAsync();

            try
            {
                var indexes = GetIndexes(shouldBreak, env, cluster);

                var appId = env.AppId;

                foreach (var index in indexes)
                {
                    Assert.Null(await index.GetAppAsync(appId.Id, true));
                    Assert.Null(await index.GetAppByNameAsync(appId.Name, true));
                }

                var creatorId     = Guid.NewGuid().ToString();
                var creatorToken  = RefToken.User(creatorId);
                var createCommand = new CreateApp {
                    Actor = creatorToken, AppId = appId.Id
                };

                var commandContext = new CommandContext(createCommand, A.Fake <ICommandBus>());

                var randomIndex = indexes[new Random().Next(3)];

                await indexes[0].HandleAsync(commandContext, x =>
                {
                    if (x.Command is CreateApp command)
                    {
                        env.HandleCommand(command);
                    }

                    x.Complete(true);

                    return(Task.CompletedTask);
                });

                foreach (var index in indexes)
                {
                    var appById = await index.GetAppAsync(appId.Id, true);

                    var appByName = await index.GetAppByNameAsync(appId.Name, true);

                    if (index == randomIndex || !shouldBreak)
                    {
                        Assert.True(appById?.Contributors.ContainsKey(creatorId));
                        Assert.True(appByName?.Contributors.ContainsKey(creatorId));
                    }
                    else
                    {
                        Assert.False(appById?.Contributors.ContainsKey(creatorId));
                        Assert.False(appByName?.Contributors.ContainsKey(creatorId));
                    }
                }
            }
            finally
            {
                await Task.WhenAny(Task.Delay(2000), cluster.StopAllSilosAsync());
            }
        }
        public async Task Should_distribute_and_cache_domain_objects(short numSilos, int numRuns, int expectedCounts, bool shouldBreak)
        {
            var env = new GrainEnvironment();

            var cluster =
                new TestClusterBuilder(numSilos)
                .AddSiloBuilderConfigurator <Configurator>()
                .Build();

            await cluster.DeployAsync();

            try
            {
                var indexes =
                    cluster.Silos.OfType <InProcessSiloHandle>()
                    .Select(x =>
                {
                    var pubSub =
                        shouldBreak ?
                        A.Fake <IPubSub>() :
                        x.SiloHost.Services.GetRequiredService <IPubSub>();

                    var cache =
                        new ReplicatedCache(
                            new MemoryCache(Options.Create(new MemoryCacheOptions())),
                            pubSub,
                            Options.Create(new ReplicatedCacheOptions {
                        Enable = true
                    }));

                    return(new SchemasIndex(env.GrainFactory, cache));
                }).ToArray();

                var appId = env.AppId;

                var random = new Random();

                for (var i = 0; i < numRuns; i++)
                {
                    var fieldName    = Guid.NewGuid().ToString();
                    var fieldCommand = new AddField {
                        Name = fieldName, SchemaId = env.SchemaId, AppId = env.AppId
                    };

                    var commandContext = new CommandContext(fieldCommand, A.Fake <ICommandBus>());

                    var randomIndex = indexes[random.Next(numSilos)];

                    await randomIndex.HandleAsync(commandContext, x =>
                    {
                        if (x.Command is AddField command)
                        {
                            env.HandleCommand(command);
                        }

                        x.Complete(true);

                        return(Task.CompletedTask);
                    });

                    foreach (var index in indexes)
                    {
                        var schemaById = await index.GetSchemaAsync(appId.Id, env.SchemaId.Id, true);

                        var schemaByName = await index.GetSchemaByNameAsync(appId.Id, env.SchemaId.Name, true);

                        if (index == randomIndex || !shouldBreak || i == 0)
                        {
                            Assert.True(schemaById?.SchemaDef.FieldsByName.ContainsKey(fieldName));
                            Assert.True(schemaByName?.SchemaDef.FieldsByName.ContainsKey(fieldName));
                        }
                        else
                        {
                            Assert.False(schemaById?.SchemaDef.FieldsByName.ContainsKey(fieldName));
                            Assert.False(schemaByName?.SchemaDef.FieldsByName.ContainsKey(fieldName));
                        }
                    }
                }

                env.VerifyGrainAccess(expectedCounts);
            }
            finally
            {
                await Task.WhenAny(Task.Delay(2000), cluster.StopAllSilosAsync());
            }
        }