diff --git a/appveyor.yml b/appveyor.yml index 5be803477..b80b67225 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,6 +15,7 @@ version: 2.0.0-preview7.{build} services: - mongodb + - postgresql101 init: - cmd: git config --global core.autocrlf true @@ -89,6 +90,16 @@ build_script: dotnet build +before_test: + - cmd: >- + SET PGUSER=postgres + + SET PGPASSWORD=Password12! + + PATH=C:\Program Files\PostgreSQL\10\bin\;%PATH% + + createdb "elsa-yessql" + test_script: - ps: dotnet test --collect:"XPlat Code Coverage" --logger:xunit -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover diff --git a/src/persistence/Elsa.Persistence.YesSql/Elsa.Persistence.YesSql.csproj b/src/persistence/Elsa.Persistence.YesSql/Elsa.Persistence.YesSql.csproj index 55a58b7bb..b37f2e08c 100644 --- a/src/persistence/Elsa.Persistence.YesSql/Elsa.Persistence.YesSql.csproj +++ b/src/persistence/Elsa.Persistence.YesSql/Elsa.Persistence.YesSql.csproj @@ -15,14 +15,8 @@ + - - - - - - - diff --git a/src/persistence/Elsa.Persistence.YesSql/Migrations.cs b/src/persistence/Elsa.Persistence.YesSql/Migrations.cs index 0777c3046..6d2fa2aa5 100644 --- a/src/persistence/Elsa.Persistence.YesSql/Migrations.cs +++ b/src/persistence/Elsa.Persistence.YesSql/Migrations.cs @@ -30,7 +30,7 @@ namespace Elsa.Persistence.YesSql .Column(nameof(WorkflowInstanceIndex.ContextId)) .Column(nameof(WorkflowInstanceIndex.ContextType)) .Column(nameof(WorkflowInstanceIndex.Name)) - .Column(nameof(WorkflowInstanceIndex.WorkflowStatus)) + .Column(nameof(WorkflowInstanceIndex.WorkflowStatus)) .Column(nameof(WorkflowInstanceIndex.CreatedAt)) .Column(nameof(WorkflowInstanceIndex.LastExecutedAt)) .Column(nameof(WorkflowInstanceIndex.FinishedAt)) diff --git a/src/persistence/Elsa.Persistence.YesSql/Services/DataMigrationManager.cs b/src/persistence/Elsa.Persistence.YesSql/Services/DataMigrationManager.cs index 4c75b28c2..bcd714e9d 100644 --- a/src/persistence/Elsa.Persistence.YesSql/Services/DataMigrationManager.cs +++ b/src/persistence/Elsa.Persistence.YesSql/Services/DataMigrationManager.cs @@ -53,6 +53,25 @@ namespace Elsa.Persistence.YesSql.Services _logger.LogError(ex, "Could not run migrations automatically on '{FeatureName}'", migration); } } + + try + { + var commitTask = _session.CurrentTransaction?.CommitAsync() ?? Task.CompletedTask; + await commitTask; + } + catch(InvalidOperationException) + { + // TODO: Improve on this ugly hack/workaround! + // + // The commit can throw this exception because it's already been committed. But if + // we don't explicitly commit here then it never gets committed and it's as if the + // migrations never took place! + // + // I suspect that either this method is being called more than once, or perhaps (IMO + // more likely) an async operation (somewhere) isn't being awaited. That could mean + // that the connection is closed/killed-off before the commit actually completes, + // with the effect that it doesn't happen. + } } public async Task> GetMigrationsThatNeedUpdateAsync() diff --git a/src/persistence/Elsa.Persistence.YesSql/Services/DatabaseInitializer.cs b/src/persistence/Elsa.Persistence.YesSql/Services/DatabaseInitializer.cs index 5040fd305..0f334bc72 100644 --- a/src/persistence/Elsa.Persistence.YesSql/Services/DatabaseInitializer.cs +++ b/src/persistence/Elsa.Persistence.YesSql/Services/DatabaseInitializer.cs @@ -22,6 +22,7 @@ namespace Elsa.Persistence.YesSql.Services await _store.InitializeCollectionAsync(CollectionNames.WorkflowDefinitions); await _store.InitializeCollectionAsync(CollectionNames.WorkflowInstances); await _store.InitializeCollectionAsync(CollectionNames.WorkflowExecutionLog); + await _store.InitializeCollectionAsync(CollectionNames.Bookmarks); } } } diff --git a/test/integration/Elsa.Core.IntegrationTests/Autofixture/WithPostgresYesSqlAttribute.cs b/test/integration/Elsa.Core.IntegrationTests/Autofixture/WithPostgresYesSqlAttribute.cs new file mode 100644 index 000000000..a19bce55e --- /dev/null +++ b/test/integration/Elsa.Core.IntegrationTests/Autofixture/WithPostgresYesSqlAttribute.cs @@ -0,0 +1,35 @@ +using System; +using Elsa.Persistence.YesSql; +using Elsa.Testing.Shared.AutoFixture.Attributes; +using Elsa.Testing.Shared.Helpers; +using YesSql; +using YesSql.Provider.PostgreSql; + +namespace Elsa.Core.IntegrationTests.Autofixture +{ + public class WithPostgresYesSqlAttribute : ElsaHostBuilderBuilderCustomizeAttributeBase + { + /// + /// This password matches the password which is used by AppVeyor: https://www.appveyor.com/docs/services-databases/#postgresql + /// + /// + /// + /// We could do something more sophisticated with the password than keep it in a constant, but since + /// this is (so far) the only place where we configure Postgres. There aren't any plans to do anything + /// with it in the foreseeable future either, so we can defer that until then. + /// + /// + internal const string PostgresPassword = "Password12!"; + + public override Action GetBuilderCustomizer() + { + return builder => { + builder.ElsaCallbacks.Add(elsa => { + elsa.UseYesSqlPersistence((IServiceProvider services, IConfiguration config) => { + config.UsePostgreSql($"Host=localhost;Database=elsa-yessql;User ID=postgres;Password={PostgresPassword}"); + }); + }); + }; + } + } +} \ No newline at end of file diff --git a/test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.csproj b/test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.csproj index 76ca1d91f..35090820c 100644 --- a/test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.csproj +++ b/test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.csproj @@ -25,6 +25,7 @@ + diff --git a/test/integration/Elsa.Core.IntegrationTests/Persistence/YesSql/PostgresSqlYesSqlIntegrationTests.cs b/test/integration/Elsa.Core.IntegrationTests/Persistence/YesSql/PostgresSqlYesSqlIntegrationTests.cs new file mode 100644 index 000000000..e4748cfda --- /dev/null +++ b/test/integration/Elsa.Core.IntegrationTests/Persistence/YesSql/PostgresSqlYesSqlIntegrationTests.cs @@ -0,0 +1,47 @@ +using System.Threading; +using System.Threading.Tasks; +using Elsa.Core.IntegrationTests.Autofixture; +using Elsa.Core.IntegrationTests.Workflows; +using Elsa.Persistence; +using Elsa.Services; +using Elsa.Testing.Shared; +using Elsa.Testing.Shared.Helpers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Xunit; + +namespace Elsa.Core.IntegrationTests.Persistence.YesSql +{ + public class PostgresSqlYesSqlIntegrationTests + { + [Theory(DisplayName = "A persistable workflow instance with default persistence behaviour should be persisted-to and readable-from a YesSQL/PostgreSql store after being run"), AutoMoqData] + public async Task APersistableWorkflowInstanceWithDefaultPersistanceBehaviourShouldBeRoundTrippable([WithPersistableWorkflow,WithPostgresYesSql] ElsaHostBuilderBuilder hostBuilderBuilder) + { + var hostBuilder = hostBuilderBuilder.GetHostBuilder(); + hostBuilder.ConfigureServices((ctx, services) => services.AddHostedService()); + var host = await hostBuilder.StartAsync(); + } + + class HostedWorkflowRunner : IHostedService + { + readonly IBuildsAndStartsWorkflow _workflowRunner; + readonly IWorkflowInstanceStore _instanceStore; + + public async Task StartAsync(CancellationToken cancellationToken) + { + var instance = await _workflowRunner.BuildAndStartWorkflowAsync(cancellationToken: cancellationToken); + var retrievedInstance = await _instanceStore.FindByIdAsync(instance.Id, cancellationToken); + + Assert.NotNull(retrievedInstance); + } + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + + public HostedWorkflowRunner(IBuildsAndStartsWorkflow workflowRunner, IWorkflowInstanceStore instanceStore) + { + _workflowRunner = workflowRunner ?? throw new System.ArgumentNullException(nameof(workflowRunner)); + _instanceStore = instanceStore ?? throw new System.ArgumentNullException(nameof(instanceStore)); + } + } + } +} \ No newline at end of file