예제 #1
0
        public void SchemaCreationIsSerializedAndIdempotent()
        {
            using TestDatabase testDb = this.CreateTestDb();
            IOrchestrationService service = this.CreateServiceWithTestDb(testDb);

            // Simulate 4 workers starting up concurrently and trying to initialize
            // the same database schema. It should just work with predictable output.
            Parallel.For(0, 4, i =>
            {
                service.CreateIfNotExistsAsync().GetAwaiter().GetResult();
            });

            ValidateDatabaseSchema(testDb);

            // Operations are expected to be serialized, making the log output deterministic.
            LogAssert.Sequence(
                this.logProvider,
                // 1st
                LogAssert.AcquiredAppLock(statusCode: 0),
                LogAssert.SprocCompleted("dt._GetVersions"),
                LogAssert.ExecutedSqlScript("schema-0.2.0.sql"),
                LogAssert.ExecutedSqlScript("logic.sql"),
                LogAssert.ExecutedSqlScript("permissions.sql"),
                LogAssert.SprocCompleted("dt._UpdateVersion"),
                // 2nd
                LogAssert.AcquiredAppLock(statusCode: 1),
                LogAssert.SprocCompleted("dt._GetVersions"),
                // 3rd
                LogAssert.AcquiredAppLock(statusCode: 1),
                LogAssert.SprocCompleted("dt._GetVersions"),
                // 4th
                LogAssert.AcquiredAppLock(statusCode: 1),
                LogAssert.SprocCompleted("dt._GetVersions"));
        }
예제 #2
0
        public async Task SingleTimer()
        {
            string   input             = $"Hello {DateTime.UtcNow:o}";
            string   orchestrationName = "OrchestrationWithTimer";
            TimeSpan delay             = TimeSpan.FromSeconds(3);

            // Performs a delay and then returns the input
            TestInstance <string> instance = await this.testService.RunOrchestration(
                input,
                orchestrationName,
                implementation : async(ctx, input) =>
            {
                var result = await ctx.CreateTimer(ctx.CurrentUtcDateTime.Add(delay), input);
                return(result);
            });

            TimeSpan           timeout = delay + TimeSpan.FromSeconds(10);
            OrchestrationState state   = await instance.WaitForCompletion(
                timeout,
                expectedOutput : input);

            // Verify that the delay actually happened
            Assert.True(state.CreatedTime.Add(delay) <= state.CompletedTime);

            // Validate logs
            LogAssert.NoWarningsOrErrors(this.testService.LogProvider);
            LogAssert.Sequence(
                this.testService.LogProvider,
                LogAssert.AcquiredAppLock(),
                LogAssert.CheckpointStarting(orchestrationName),
                LogAssert.CheckpointCompleted(orchestrationName),
                LogAssert.CheckpointStarting(orchestrationName),
                LogAssert.CheckpointCompleted(orchestrationName));
        }
예제 #3
0
        public async Task CanCreateIfNotExists(bool isDatabaseMissing)
        {
            using TestDatabase testDb = this.CreateTestDb(!isDatabaseMissing);
            IOrchestrationService service = this.CreateServiceWithTestDb(testDb);

            await service.CreateIfNotExistsAsync();

            LogAssert.NoWarningsOrErrors(this.logProvider);
            LogAssert
            .For(this.logProvider)
            .Expect(
                LogAssert.CheckedDatabase())
            .ExpectIf(
                isDatabaseMissing,
                LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"),
                LogAssert.CreatedDatabase(testDb.Name))
            .Expect(
                LogAssert.AcquiredAppLock(),
                LogAssert.SprocCompleted("dt._GetVersions"),
                LogAssert.ExecutedSqlScript("schema-0.2.0.sql"),
                LogAssert.ExecutedSqlScript("logic.sql"),
                LogAssert.ExecutedSqlScript("permissions.sql"),
                LogAssert.SprocCompleted("dt._UpdateVersion"))
            .EndOfLog();

            ValidateDatabaseSchema(testDb);
        }
예제 #4
0
        public async Task CanCreateAndDropSchema(bool isDatabaseMissing)
        {
            using TestDatabase testDb = this.CreateTestDb(!isDatabaseMissing);
            IOrchestrationService service = this.CreateServiceWithTestDb(testDb);

            // Create the DB schema for the first time
            await service.CreateAsync(recreateInstanceStore : true);

            LogAssert.NoWarningsOrErrors(this.logProvider);
            LogAssert
            .For(this.logProvider)
            .Expect(
                LogAssert.CheckedDatabase())
            .ExpectIf(
                isDatabaseMissing,
                LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"),
                LogAssert.CreatedDatabase(testDb.Name))
            .Expect(
                LogAssert.AcquiredAppLock(),
                LogAssert.ExecutedSqlScript("drop-schema.sql"),
                LogAssert.ExecutedSqlScript("schema-0.2.0.sql"),
                LogAssert.ExecutedSqlScript("logic.sql"),
                LogAssert.ExecutedSqlScript("permissions.sql"),
                LogAssert.SprocCompleted("dt._UpdateVersion"))
            .EndOfLog();

            ValidateDatabaseSchema(testDb);

            // Create the DB schema again - should be a no-op since it already exists
            this.logProvider.Clear();
            await service.CreateIfNotExistsAsync();

            ValidateDatabaseSchema(testDb);

            // The subsequent execution should run exactly one sproc and no scripts.
            // It's important to verify this to ensure the overhead of CreateIfNotExistsAsync is very small.
            LogAssert.NoWarningsOrErrors(this.logProvider);
            LogAssert.Sequence(
                this.logProvider,
                LogAssert.CheckedDatabase(),
                LogAssert.AcquiredAppLock(),
                LogAssert.SprocCompleted("dt._GetVersions"));

            // Delete the database and validate
            this.logProvider.Clear();
            await service.DeleteAsync();

            LogAssert.NoWarningsOrErrors(this.logProvider);
            LogAssert.Sequence(
                this.logProvider,
                LogAssert.AcquiredAppLock(),
                LogAssert.ExecutedSqlScript("drop-schema.sql"));

            // The previous schema validation ensures all objects are in the "dt" schema.
            // We know that all objects were successfully removed if the "dt" no longer exists.
            Assert.DoesNotContain("dt", testDb.GetSchemas());
        }
예제 #5
0
        public void SchemaCreationIsSerializedAndIdempotent(bool isDatabaseMissing)
        {
            using TestDatabase testDb = this.CreateTestDb(!isDatabaseMissing);
            IOrchestrationService service = this.CreateServiceWithTestDb(testDb);

            // Simulate 4 workers starting up concurrently and trying to initialize
            // the same database schema. It should just work with predictable output.
            Parallel.For(0, 4, i =>
            {
                service.CreateIfNotExistsAsync().GetAwaiter().GetResult();
            });

            ValidateDatabaseSchema(testDb);

            // Operations are expected to be serialized, making the log output deterministic.
            LogAssert
            .For(this.logProvider)
            .Expect(
                // At least 1 worker will check the database first
                LogAssert.CheckedDatabase())
            .Contains(
                // The other 3 workers will check in some non-deterministic order
                LogAssert.CheckedDatabase(),
                LogAssert.CheckedDatabase(),
                LogAssert.CheckedDatabase())
            .ContainsIf(
                // One worker may obtain the lock after another worker created the database.
                isDatabaseMissing,
                LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"),
                LogAssert.CreatedDatabase(testDb.Name))
            .OptionallyContainsIf(
                // Anywhere from 0 to 3 of the workers may end up attempting to create the database.
                isDatabaseMissing,
                LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"),
                LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"),
                LogAssert.CommandCompleted($"CREATE DATABASE [{testDb.Name}]"))
            .Expect(
                // 1st
                LogAssert.AcquiredAppLock(statusCode: 0),
                LogAssert.SprocCompleted("dt._GetVersions"),
                LogAssert.ExecutedSqlScript("schema-0.2.0.sql"),
                LogAssert.ExecutedSqlScript("logic.sql"),
                LogAssert.ExecutedSqlScript("permissions.sql"),
                LogAssert.SprocCompleted("dt._UpdateVersion"),
                // 2nd
                LogAssert.AcquiredAppLock(),
                LogAssert.SprocCompleted("dt._GetVersions"),
                // 3rd
                LogAssert.AcquiredAppLock(),
                LogAssert.SprocCompleted("dt._GetVersions"),
                // 4th
                LogAssert.AcquiredAppLock(),
                LogAssert.SprocCompleted("dt._GetVersions"))
            .EndOfLog();
        }
예제 #6
0
        public async Task CanCreateIfNotExists()
        {
            using TestDatabase testDb = this.CreateTestDb();
            IOrchestrationService service = this.CreateServiceWithTestDb(testDb);

            await service.CreateIfNotExistsAsync();

            LogAssert.NoWarningsOrErrors(this.logProvider);
            LogAssert.Sequence(
                this.logProvider,
                LogAssert.AcquiredAppLock(),
                LogAssert.SprocCompleted("dt._GetVersions"),
                LogAssert.ExecutedSqlScript("schema-0.2.0.sql"),
                LogAssert.ExecutedSqlScript("logic.sql"),
                LogAssert.ExecutedSqlScript("permissions.sql"),
                LogAssert.SprocCompleted("dt._UpdateVersion"));

            ValidateDatabaseSchema(testDb);
        }
예제 #7
0
        public async Task EmptyOrchestration()
        {
            string input             = $"Hello {DateTime.UtcNow:o}";
            string orchestrationName = "EmptyOrchestration";

            // Does nothing except return the original input
            TestInstance <string> instance = await this.testService.RunOrchestration(
                input,
                orchestrationName,
                implementation : (ctx, input) => Task.FromResult(input));

            await instance.WaitForCompletion(
                expectedOutput : input);

            // Validate logs
            LogAssert.NoWarningsOrErrors(this.testService.LogProvider);
            LogAssert.Sequence(
                this.testService.LogProvider,
                LogAssert.AcquiredAppLock(),
                LogAssert.CheckpointStarting(orchestrationName),
                LogAssert.CheckpointCompleted(orchestrationName));
        }