diff --git a/build-system/README.md b/build-system/README.md new file mode 100644 index 0000000..699c2d4 --- /dev/null +++ b/build-system/README.md @@ -0,0 +1,8 @@ +# Azure Pipelines Build Files +These `.yaml` files are used by Windows Azure DevOps Pipelines to help execute the following types of builds: + +- Pull request validation on Linux (Mono / .NET Core) +- Pull request validation on Windows (.NET Framework / .NET Core) +- NuGet releases with automatic release notes posted to a Github Release repository. + +**NOTE**: you will need to change some of the pipeline variables inside the `windows-release.yaml` for your specific project and you will also want to create variable groups with your signing and NuGet push information. \ No newline at end of file diff --git a/build-system/azure-pipeline.template.yaml b/build-system/azure-pipeline.template.yaml new file mode 100644 index 0000000..a3663c3 --- /dev/null +++ b/build-system/azure-pipeline.template.yaml @@ -0,0 +1,63 @@ +parameters: + name: '' + vmImage: '' + displayName: '' + artifactName: 'akkaBuild' + scriptFileName: '' + scriptArgs: 'all' + outputDirectory: '' + timeoutInMinutes: 120 + +jobs: + - job: ${{ parameters.name }} + displayName: ${{ parameters.displayName }} + timeoutInMinutes: ${{ parameters.timeoutInMinutes }} + pool: + vmImage: ${{ parameters.vmImage }} + steps: + - checkout: self # self represents the repo where the initial Pipelines YAML file was found + clean: false # whether to fetch clean each time + submodules: recursive # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules + persistCredentials: true + - task: UseDotNet@2 + displayName: 'Use .NET Core Runtime 3.1.10' + inputs: + packageType: runtime + version: 3.1.10 + # Linux or macOS + - task: Bash@3 + displayName: Linux / OSX Build + inputs: + filePath: ${{ parameters.scriptFileName }} + arguments: ${{ parameters.scriptArgs }} + continueOnError: true + condition: in( variables['Agent.OS'], 'Linux', 'Darwin' ) + # Windows test is disabled, could not use redis container in Azure Pipelines +# - task: BatchScript@1 +# displayName: Windows Build +# inputs: +# filename: ${{ parameters.scriptFileName }} +# arguments: ${{ parameters.scriptArgs }} +# continueOnError: true +# condition: eq( variables['Agent.OS'], 'Windows_NT' ) + - task: PublishTestResults@2 + inputs: + testRunner: VSTest + testResultsFiles: '**/*.trx' #TestResults folder usually + testRunTitle: ${{ parameters.name }} + mergeTestResults: true + - task: CopyFiles@2 + displayName: 'Copy Build Output' + inputs: + sourceFolder: ${{ parameters.outputDirectory }} + contents: '**\*' + targetFolder: $(Build.ArtifactStagingDirectory) + continueOnError: boolean # 'true' if future steps should run even if this step fails; defaults to 'false' + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: '$(Build.ArtifactStagingDirectory)' + artifactName: ${{ parameters.artifactName }} + - script: 'echo 1>&2' + failOnStderr: true + displayName: 'If above is partially succeeded, then fail' + condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues') \ No newline at end of file diff --git a/build-system/pr-validation.yaml b/build-system/pr-validation.yaml new file mode 100644 index 0000000..87e3618 --- /dev/null +++ b/build-system/pr-validation.yaml @@ -0,0 +1,34 @@ +# Pull request validation for Windows against the `dev` and `master` branches +# See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference +trigger: + branches: + include: + - dev + - master + +pr: + autoCancel: true # indicates whether additional pushes to a PR should cancel in-progress runs for the same PR. Defaults to true + branches: + include: [ dev, master ] # branch names which will trigger a build + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r) + +jobs: + # Windows testing is disabled, Redis linux container can not run in windows docker. +# - template: azure-pipeline.template.yaml +# parameters: +# name: 'windows_pr' +# displayName: 'Windows PR Validation' +# vmImage: 'windows-2019' +# scriptFileName: build.cmd +# scriptArgs: all + + - template: azure-pipeline.template.yaml + parameters: + name: 'linux_pr' + displayName: 'Linux PR Validation' + vmImage: 'ubuntu-16.04' + scriptFileName: './build.sh' + scriptArgs: RunTestsNetCore + outputDirectory: 'TestResults' + artifactName: 'net_core_tests-$(Build.BuildId)' \ No newline at end of file diff --git a/build-system/windows-release.yaml b/build-system/windows-release.yaml new file mode 100644 index 0000000..2c707cf --- /dev/null +++ b/build-system/windows-release.yaml @@ -0,0 +1,43 @@ +# Release task for PbLib projects +# See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference + +pool: + vmImage: vs2017-win2016 + demands: Cmd + +trigger: + branches: + include: + - refs/tags/* +pr: none + +variables: + - group: signingSecrets #create this group with SECRET variables `signingUsername` and `signingPassword` + - group: nugetKeys #create this group with SECRET variables `nugetKey` + - name: githubConnectionName + value: AkkaDotNet_Releases + - name: projectName + value: Akka.Persistence.PostgreSql + - name: githubRepositoryName + value: akkadotnet/Akka.Persistence.PostgreSql +steps: +- task: UseDotNet@2 + displayName: 'Use .NET Core Runtime 3.1.10' + inputs: + packageType: runtime + version: 3.1.10 +- task: BatchScript@1 + displayName: 'FAKE Build' + inputs: + filename: build.cmd + arguments: 'Nuget SignClientUser=$(signingUsername) SignClientSecret=$(signingPassword) nugetpublishurl=https://www.nuget.org/api/v2/package nugetkey=$(nugetKey)' + +- task: GitHubRelease@0 + displayName: 'GitHub release (create)' + inputs: + gitHubConnection: $(githubConnectionName) + repositoryName: $(githubRepositoryName) + title: '$(projectName) v$(Build.SourceBranchName)' + releaseNotesFile: 'RELEASE_NOTES.md' + assets: | + bin\nuget\*.nupkg diff --git a/build.fsx b/build.fsx index da1bc70..49ccef6 100644 --- a/build.fsx +++ b/build.fsx @@ -7,44 +7,47 @@ open System.Text open Fake open Fake.DotNetCli +open Fake.DocFxHelper +open Fake.NuGet.Install -//-------------------------------------------------------------------------------- -// Information about the project for Nuget and Assembly info files -//-------------------------------------------------------------------------------- - -let product = "Akka.NET" -let authors = [ "Akka.NET Team" ] -let copyright = "Copyright © 2013-2015 Akka.NET Team" -let company = "Akka.NET Team" -let description = "Akka.NET is a port of the popular Java/Scala framework Akka to .NET" -let tags = ["akka";"actors";"actor";"model";"Akka";"concurrency"] +// Variables let configuration = "Release" +let solution = System.IO.Path.GetFullPath(string "./src/Akka.Persistence.PostgreSql.sln") -//-------------------------------------------------------------------------------- // Directories -//-------------------------------------------------------------------------------- - -let slnFile = __SOURCE_DIRECTORY__ @@ "src/Akka.Persistence.PostgreSql.sln" +let toolsDir = __SOURCE_DIRECTORY__ @@ "tools" let output = __SOURCE_DIRECTORY__ @@ "bin" -let outputTests = output @@ "TestResults" -let outputPerfTests = output @@ "perf" +let outputTests = __SOURCE_DIRECTORY__ @@ "TestResults" +let outputPerfTests = __SOURCE_DIRECTORY__ @@ "PerfResults" let outputBinaries = output @@ "binaries" let outputNuGet = output @@ "nuget" -let outputBinariesNet45 = outputBinaries @@ "net45" -let outputBinariesNetStandard = outputBinaries @@ "netstandard1.6" +let outputBinariesNet47 = outputBinaries @@ "net471" +let outputBinariesNetStandard = outputBinaries @@ "netstandard2.0" // Read release notes and version let buildNumber = environVarOrDefault "BUILD_NUMBER" "0" -let preReleaseVersionSuffix = (if (not (buildNumber = "0")) then (buildNumber) else "") + "-beta" -let versionSuffix = - match (getBuildParam "nugetprerelease") with - | "dev" -> preReleaseVersionSuffix - | _ -> "" +let preReleaseVersionSuffix = "beta" + (if (not (buildNumber = "0")) then (buildNumber) else DateTime.UtcNow.Ticks.ToString()) let releaseNotes = - File.ReadLines "./RELEASE_NOTES.md" + File.ReadLines (__SOURCE_DIRECTORY__ @@ "RELEASE_NOTES.md") |> ReleaseNotesHelper.parseReleaseNotes +let versionFromReleaseNotes = + match releaseNotes.SemVer.PreRelease with + | Some r -> r.Origin + | None -> "" + +let versionSuffix = + match (getBuildParam "nugetprerelease") with + | "dev" -> preReleaseVersionSuffix + | "" -> versionFromReleaseNotes + | str -> str + +// Configuration values for tests +let testNetFrameworkVersion = "net471" +let testNetCoreVersion = "netcoreapp3.1" +let testNetVersion = "net5.0" + printfn "Assembly version: %s\nNuget version; %s\n" releaseNotes.AssemblyVersion releaseNotes.NugetVersion //-------------------------------------------------------------------------------- @@ -52,11 +55,17 @@ printfn "Assembly version: %s\nNuget version; %s\n" releaseNotes.AssemblyVersion //-------------------------------------------------------------------------------- Target "Clean" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + CleanDir output CleanDir outputTests CleanDir outputPerfTests + CleanDir outputBinaries CleanDir outputNuGet + CleanDir outputBinariesNet47 + CleanDir outputBinariesNetStandard CleanDir "docs/_site" + CleanDirs !! "./**/bin" CleanDirs !! "./**/obj" ) @@ -69,8 +78,8 @@ Target "RestorePackages" (fun _ -> DotNetCli.Restore (fun p -> { p with - Project = slnFile - NoCache = false }) + Project = solution + NoCache = true }) ) //-------------------------------------------------------------------------------- @@ -106,6 +115,22 @@ Target "Build" (fun _ -> // Run tests //-------------------------------------------------------------------------------- +type Runtime = + | NetCore + | Net + | NetFramework + +let getTestAssembly runtime project = + let assemblyPath = match runtime with + | NetCore -> !! ("src" @@ "**" @@ "bin" @@ "Release" @@ testNetCoreVersion @@ fileNameWithoutExt project + ".dll") + | NetFramework -> !! ("src" @@ "**" @@ "bin" @@ "Release" @@ testNetFrameworkVersion @@ fileNameWithoutExt project + ".dll") + | Net -> !! ("src" @@ "**" @@ "bin" @@ "Release" @@ testNetVersion @@ fileNameWithoutExt project + ".dll") + + if Seq.isEmpty assemblyPath then + None + else + Some (assemblyPath |> Seq.head) + module internal ResultHandling = let (|OK|Failure|) = function | 0 -> OK @@ -125,62 +150,55 @@ module internal ResultHandling = >> Option.iter (failBuildWithMessage errorLevel) Target "RunTests" <| fun _ -> - let projects = - match (isWindows) with - | true -> !! "./src/**/*.Tests.csproj" - | _ -> !! "./src/**/*.Tests.csproj" // if you need to filter specs for Linux vs. Windows, do it here + let projects = + match (isWindows) with + | true -> !! "./src/**/*.Tests.*sproj" + | _ -> !! "./src/**/*.Tests.*sproj" // if you need to filter specs for Linux vs. Windows, do it here ensureDirectory outputTests let runSingleProject project = + let arguments = + (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --framework %s --results-directory \"%s\" -- -parallel none" testNetFrameworkVersion outputTests) + let result = ExecProcess(fun info -> info.FileName <- "dotnet" info.WorkingDirectory <- (Directory.GetParent project).FullName - info.Arguments <- (sprintf "xunit -f net452 -c Release -parallel none -teamcity -xml %s_net452_xunit.xml" (outputTests @@ fileNameWithoutExt project))) (TimeSpan.FromMinutes 30.) - - ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.DontFailBuild result + info.Arguments <- arguments) (TimeSpan.FromMinutes 30.0) - // dotnet process will be killed by ExecProcess (or throw if can't) ' - // but per https://github.com/xunit/xunit/issues/1338 xunit.console may not - killProcess "xunit.console" - killProcess "dotnet" + ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.Error result - projects |> Seq.iter (log) + CreateDir outputTests projects |> Seq.iter (runSingleProject) Target "RunTestsNetCore" <| fun _ -> - let projects = - match (isWindows) with - | true -> !! "./src/**/*.Tests.csproj" - | _ -> !! "./src/**/*.Tests.csproj" // if you need to filter specs for Linux vs. Windows, do it here + let projects = + match (isWindows) with + | true -> !! "./src/**/*.Tests.*sproj" + | _ -> !! "./src/**/*.Tests.*sproj" // if you need to filter specs for Linux vs. Windows, do it here ensureDirectory outputTests let runSingleProject project = + let arguments = + (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --framework %s --results-directory \"%s\" -- -parallel none" testNetCoreVersion outputTests) + let result = ExecProcess(fun info -> info.FileName <- "dotnet" info.WorkingDirectory <- (Directory.GetParent project).FullName - info.Arguments <- (sprintf "xunit -f netcoreapp1.1 -c Release -parallel none -teamcity -xml %s_netcore_xunit.xml" (outputTests @@ fileNameWithoutExt project))) (TimeSpan.FromMinutes 30.) - - ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.DontFailBuild result + info.Arguments <- arguments) (TimeSpan.FromMinutes 30.0) - // dotnet process will be killed by ExecProcess (or throw if can't) ' - // but per https://github.com/xunit/xunit/issues/1338 xunit.console may not - killProcess "xunit.console" - killProcess "dotnet" + ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.Error result - projects |> Seq.iter (log) + CreateDir outputTests projects |> Seq.iter (runSingleProject) //-------------------------------------------------------------------------------- // Nuget targets //-------------------------------------------------------------------------------- -let overrideVersionSuffix (project:string) = - match project with - | _ -> versionSuffix // add additional matches to publish different versions for different projects in solution - Target "CreateNuget" (fun _ -> + CreateDir outputNuGet // need this to stop Azure pipelines copy stage from error-ing out let projects = !! "src/**/*.csproj" -- "src/**/*Tests.csproj" // Don't publish unit tests -- "src/**/*Tests*.csproj" @@ -192,13 +210,14 @@ Target "CreateNuget" (fun _ -> Project = project Configuration = configuration AdditionalArgs = ["--include-symbols"] - VersionSuffix = overrideVersionSuffix project - OutputPath = outputNuGet }) + VersionSuffix = versionSuffix + OutputPath = "\"" + outputNuGet + "\"" }) projects |> Seq.iter (runSingleProject) ) Target "PublishNuget" (fun _ -> + let projects = !! "./bin/nuget/*.nupkg" -- "./bin/nuget/*.symbols.nupkg" let apiKey = getBuildParamOrDefault "nugetkey" "" let source = getBuildParamOrDefault "nugetpublishurl" "" @@ -225,6 +244,14 @@ Target "PublishNuget" (fun _ -> projects |> Seq.iter (runSingleProject) ) +FinalTarget "KillCreatedProcesses" (fun _ -> + log "Shutting down dotnet build-server" + let result = ExecProcess(fun info -> + info.FileName <- "dotnet" + info.WorkingDirectory <- __SOURCE_DIRECTORY__ + info.Arguments <- "build-server shutdown") (System.TimeSpan.FromMinutes 2.0) + if result <> 0 then failwithf "dotnet build-server shutdown failed" +) //-------------------------------------------------------------------------------- // Help @@ -328,22 +355,24 @@ Target "HelpDocs" <| fun _ -> //-------------------------------------------------------------------------------- Target "BuildRelease" DoNothing +Target "All" DoNothing Target "Nuget" DoNothing // build dependencies -"Clean" ==> "AssemblyInfo" ==> "RestorePackages" ==> "Build" ==> "BuildRelease" +"Clean" ==> "AssemblyInfo" ==> "Build" +"Build" ==> "BuildRelease" // test dependencies -"RestorePackages" ==> "RunTests" -"RestorePackages" ==> "RunTestsNetCore" +"Build" ==> "RunTests" +"Build" ==> "RunTestsNetCore" // nuget dependencies "BuildRelease" ==> "CreateNuget" "CreateNuget" ==> "PublishNuget" ==> "Nuget" -Target "All" DoNothing "BuildRelease" ==> "All" "RunTests" ==> "All" +"RunTestsNetCore" ==> "All" "Nuget" ==> "All" RunTargetOrDefault "Help" diff --git a/build.ps1 b/build.ps1 index 48cd53e..8e20528 100644 --- a/build.ps1 +++ b/build.ps1 @@ -31,9 +31,9 @@ Param( $FakeVersion = "4.61.2" $NBenchVersion = "1.0.1" -$DotNetChannel = "preview"; -$DotNetVersion = "1.0.4"; -$DotNetInstallerUri = "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.ps1"; +$DotNetChannel = "LTS"; +$DotNetVersion = "3.1.100"; +$DotNetInstallerUri = "https://dot.net/v1/dotnet-install.ps1"; $NugetVersion = "4.1.0"; $NugetUrl = "https://dist.nuget.org/win-x86-commandline/v$NugetVersion/nuget.exe" $ProtobufVersion = "3.2.0" diff --git a/build.sh b/build.sh index 5e653dd..d53ef36 100644 --- a/build.sh +++ b/build.sh @@ -7,11 +7,13 @@ SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) TOOLS_DIR=$SCRIPT_DIR/tools NUGET_EXE=$TOOLS_DIR/nuget.exe -NUGET_URL=https://dist.nuget.org/win-x86-commandline/v4.0.0/nuget.exe -FAKE_VERSION=4.61.2 +NUGET_URL=https://dist.nuget.org/win-x86-commandline/v5.8.0/nuget.exe +FAKE_VERSION=4.63.0 FAKE_EXE=$TOOLS_DIR/FAKE/tools/FAKE.exe -DOTNET_VERSION=1.0.4 -DOTNET_INSTALLER_URL=https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh +DOTNET_EXE=$SCRIPT_DIR/.dotnet/dotnet +DOTNETCORE_VERSION=3.1.105 +DOTNET_INSTALLER_URL=https://dot.net/v1/dotnet-install.sh +DOTNET_CHANNEL=LTS # Define default arguments. TARGET="Default" @@ -38,22 +40,6 @@ if [ ! -d "$TOOLS_DIR" ]; then mkdir "$TOOLS_DIR" fi -########################################################################### -# INSTALL .NET CORE CLI -########################################################################### - -echo "Installing .NET CLI..." -if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then - mkdir "$SCRIPT_DIR/.dotnet" -fi -curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" $DOTNET_INSTALLER_URL -bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --install-dir .dotnet --no-path -export PATH="$SCRIPT_DIR/.dotnet":$PATH -export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 -export DOTNET_CLI_TELEMETRY_OPTOUT=1 -chmod -R 0755 ".dotnet" -"$SCRIPT_DIR/.dotnet/dotnet" --info - ########################################################################### # INSTALL NUGET ########################################################################### diff --git a/src/Akka.Persistence.PostgreSql.Tests/Akka.Persistence.PostgreSql.Tests.csproj b/src/Akka.Persistence.PostgreSql.Tests/Akka.Persistence.PostgreSql.Tests.csproj index 5655bf3..f67866a 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/Akka.Persistence.PostgreSql.Tests.csproj +++ b/src/Akka.Persistence.PostgreSql.Tests/Akka.Persistence.PostgreSql.Tests.csproj @@ -2,30 +2,20 @@ - net452;netcoreapp1.1 + $(NetFrameworkTestVersion);$(NetCoreTestVersion) false - - - - - - + + + - - + - - - Always - - - diff --git a/src/Akka.Persistence.PostgreSql.Tests/DbUtils.cs b/src/Akka.Persistence.PostgreSql.Tests/DbUtils.cs index e72be35..56b7d07 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/DbUtils.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/DbUtils.cs @@ -5,23 +5,18 @@ // //----------------------------------------------------------------------- -using Microsoft.Extensions.Configuration; using Npgsql; using System; -using System.IO; namespace Akka.Persistence.PostgreSql.Tests { public static class DbUtils { - public static IConfigurationRoot Config { get; private set; } public static string ConnectionString { get; private set; } - public static void Initialize() + public static void Initialize(PostgresFixture fixture) { - Config = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) - .AddXmlFile("app.xml").Build(); - ConnectionString = Config.GetSection("connectionStrings:add:TestDb")["connectionString"]; + ConnectionString = fixture.ConnectionString; var connectionBuilder = new NpgsqlConnectionStringBuilder(ConnectionString); //connect to postgres database to create a new database @@ -36,7 +31,7 @@ public static void Initialize() bool dbExists; using (var cmd = new NpgsqlCommand()) { - cmd.CommandText = string.Format(@"SELECT TRUE FROM pg_database WHERE datname='{0}'", databaseName); + cmd.CommandText = $@"SELECT TRUE FROM pg_database WHERE datname='{databaseName}'"; cmd.Connection = conn; var result = cmd.ExecuteScalar(); @@ -56,8 +51,6 @@ public static void Initialize() public static void Clean() { - var connectionBuilder = new NpgsqlConnectionStringBuilder(ConnectionString); - using (var conn = new NpgsqlConnection(ConnectionString)) { conn.Open(); @@ -70,7 +63,7 @@ private static void DoCreate(NpgsqlConnection conn, string databaseName) { using (var cmd = new NpgsqlCommand()) { - cmd.CommandText = string.Format(@"CREATE DATABASE {0}", databaseName); + cmd.CommandText = $@"CREATE DATABASE {databaseName}"; cmd.Connection = conn; cmd.ExecuteNonQuery(); } diff --git a/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlJournalJsonSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlJournalJsonSpec.cs index 4ba96e9..4e17779 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlJournalJsonSpec.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlJournalJsonSpec.cs @@ -15,15 +15,13 @@ namespace Akka.Persistence.PostgreSql.Tests.Json [Collection("PostgreSqlSpec")] public class PostgreSqlJournalJsonSpec : JournalSpec { - private static readonly Config SpecConfig; - - static PostgreSqlJournalJsonSpec() + private static Config Initialize(PostgresFixture fixture) { //need to make sure db is created before the tests start - DbUtils.Initialize(); + DbUtils.Initialize(fixture); - var config = @" - akka.persistence { + return ConfigurationFactory.ParseString(@" + akka.persistence { publish-plugin-commands = on journal { plugin = ""akka.persistence.journal.postgresql"" @@ -37,13 +35,14 @@ class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistenc stored-as = ""jsonb"" } } - }"; - - SpecConfig = ConfigurationFactory.ParseString(config); + }"); } - public PostgreSqlJournalJsonSpec(ITestOutputHelper output) - : base(SpecConfig, "PostgreSqlJournalJsonSpec", output: output) + // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811 + protected override bool SupportsSerialization => false; + + public PostgreSqlJournalJsonSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), "PostgreSqlJournalJsonSpec", output: output) { Initialize(); } diff --git a/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlSnapshotStoreJsonSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlSnapshotStoreJsonSpec.cs index 265eab1..ab8f9a1 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlSnapshotStoreJsonSpec.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/Json/PostgreSqlSnapshotStoreJsonSpec.cs @@ -15,15 +15,13 @@ namespace Akka.Persistence.PostgreSql.Tests.Json [Collection("PostgreSqlSpec")] public class PostgreSqlSnapshotStoreJsonSpec : SnapshotStoreSpec { - private static readonly Config SpecConfig; - - static PostgreSqlSnapshotStoreJsonSpec() + private static Config Initialize(PostgresFixture fixture) { //need to make sure db is created before the tests start - DbUtils.Initialize(); + DbUtils.Initialize(fixture); - var config = @" - akka.persistence { + return ConfigurationFactory.ParseString(@" + akka.persistence { publish-plugin-commands = on snapshot-store { plugin = ""akka.persistence.snapshot-store.postgresql"" @@ -37,17 +35,19 @@ class = ""Akka.Persistence.PostgreSql.Snapshot.PostgreSqlSnapshotStore, Akka.Per stored-as = ""JSONB"" } } - }"; - - SpecConfig = ConfigurationFactory.ParseString(config); + }"); } - public PostgreSqlSnapshotStoreJsonSpec(ITestOutputHelper output) - : base(SpecConfig, "PostgreSqlSnapshotStoreJsonSpec", output: output) + + public PostgreSqlSnapshotStoreJsonSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), "PostgreSqlSnapshotStoreJsonSpec", output: output) { Initialize(); } + // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811 + protected override bool SupportsSerialization => false; + protected override void Dispose(bool disposing) { base.Dispose(disposing); diff --git a/src/Akka.Persistence.PostgreSql.Tests/Performance/PostgreSqlJournalPerfSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Performance/PostgreSqlJournalPerfSpec.cs new file mode 100644 index 0000000..5305561 --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Performance/PostgreSqlJournalPerfSpec.cs @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2021 Lightbend Inc. +// Copyright (C) 2013-2021 .NET Foundation +// +//----------------------------------------------------------------------- + +using System; +using Akka.Configuration; +using Akka.Persistence.TestKit.Performance; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Performance +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlJournalPerfSpec : JournalPerfSpec + { + public PostgreSqlJournalPerfSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(CreateSpecConfig(fixture), "PostgreSqlJournalPerfSpec", output) + { + EventsCount = 5 * 1000; + ExpectDuration = TimeSpan.FromSeconds(60); + } + + private static Config CreateSpecConfig(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString(@" + akka.loglevel = INFO + akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" + akka.persistence.journal.postgresql { + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + auto-initialize = on + connection-string = """ + DbUtils.ConnectionString + @""" + } + akka.test.single-expect-default = 3s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} diff --git a/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlJournalConnectionFailureSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlJournalConnectionFailureSpec.cs new file mode 100644 index 0000000..5cf7389 --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlJournalConnectionFailureSpec.cs @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2016 Lightbend Inc. +// Copyright (C) 2013-2016 Akka.NET project +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.Sql.TestKit; +using Akka.Persistence.TCK.Journal; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlJournalConnectionFailureSpec : SqlJournalConnectionFailureSpec + { + private static Config Initialize(PostgresFixture fixture, string connectionString) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + var config = @" + akka.persistence { + publish-plugin-commands = on + journal { + plugin = ""akka.persistence.journal.postgresql"" + postgresql { + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + schema-name = public + auto-initialize = on + connection-string = """ + connectionString + @""" + } + } + }"; + + return ConfigurationFactory.ParseString(config); + } + + public PostgreSqlJournalConnectionFailureSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture, DefaultInvalidConnectionString), output: output) + { + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlJournalSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlJournalSpec.cs index 4af6baf..bb87fa0 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlJournalSpec.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlJournalSpec.cs @@ -15,12 +15,10 @@ namespace Akka.Persistence.PostgreSql.Tests [Collection("PostgreSqlSpec")] public class PostgreSqlJournalSpec : JournalSpec { - private static readonly Config SpecConfig; - - static PostgreSqlJournalSpec() + private static Config Initialize(PostgresFixture fixture) { //need to make sure db is created before the tests start - DbUtils.Initialize(); + DbUtils.Initialize(fixture); var config = @" akka.persistence { @@ -38,11 +36,14 @@ class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistenc } }"; - SpecConfig = ConfigurationFactory.ParseString(config); + return ConfigurationFactory.ParseString(config); } - public PostgreSqlJournalSpec(ITestOutputHelper output) - : base(SpecConfig, "PostgreSqlJournalSpec", output: output) + // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811 + protected override bool SupportsSerialization => false; + + public PostgreSqlJournalSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), "PostgreSqlJournalSpec", output: output) { Initialize(); } diff --git a/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlSnapshotStoreConnectionFailureSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlSnapshotStoreConnectionFailureSpec.cs new file mode 100644 index 0000000..9d991dd --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlSnapshotStoreConnectionFailureSpec.cs @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2016 Lightbend Inc. +// Copyright (C) 2013-2016 Akka.NET project +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.Snapshot; +using Akka.Persistence.Sql.TestKit; +using Akka.Persistence.TCK.Snapshot; +using Akka.TestKit; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlSnapshotStoreConnectionFailureSpec : SqlSnapshotConnectionFailureSpec + { + private static Config Initialize(PostgresFixture fixture, string connectionString) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + var config = @" + akka.persistence { + publish-plugin-commands = on + snapshot-store { + plugin = ""akka.persistence.snapshot-store.postgresql"" + postgresql { + class = ""Akka.Persistence.PostgreSql.Snapshot.PostgreSqlSnapshotStore, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = snapshot_store + schema-name = public + auto-initialize = on + connection-string = """ + connectionString + @""" + } + } + }"; + + return ConfigurationFactory.ParseString(config); + } + + public PostgreSqlSnapshotStoreConnectionFailureSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture, DefaultInvalidConnectionString), output: output) + { + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlSnapshotStoreSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlSnapshotStoreSpec.cs index 29306aa..93486ec 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlSnapshotStoreSpec.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/PostgreSqlSnapshotStoreSpec.cs @@ -16,12 +16,10 @@ namespace Akka.Persistence.PostgreSql.Tests [Collection("PostgreSqlSpec")] public class PostgreSqlSnapshotStoreSpec : SnapshotStoreSpec { - private static readonly Config SpecConfig; - - static PostgreSqlSnapshotStoreSpec() + private static Config Initialize(PostgresFixture fixture) { //need to make sure db is created before the tests start - DbUtils.Initialize(); + DbUtils.Initialize(fixture); var config = @" akka.persistence { @@ -39,11 +37,11 @@ class = ""Akka.Persistence.PostgreSql.Snapshot.PostgreSqlSnapshotStore, Akka.Per } }"; - SpecConfig = ConfigurationFactory.ParseString(config); + return ConfigurationFactory.ParseString(config); } - public PostgreSqlSnapshotStoreSpec(ITestOutputHelper output) - : base(SpecConfig, "PostgreSqlSnapshotStoreSpec", output: output) + public PostgreSqlSnapshotStoreSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), "PostgreSqlSnapshotStoreSpec", output: output) { Initialize(); } diff --git a/src/Akka.Persistence.PostgreSql.Tests/PostgresFixture.cs b/src/Akka.Persistence.PostgreSql.Tests/PostgresFixture.cs new file mode 100644 index 0000000..48158ec --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/PostgresFixture.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Akka.Util; +using Docker.DotNet; +using Docker.DotNet.Models; +using Xunit; + +namespace Akka.Persistence.PostgreSql.Tests +{ + [CollectionDefinition("PostgreSqlSpec")] + public sealed class PostgresSpecsFixture : ICollectionFixture + { + } + + /// + /// Fixture used to run PostgresSQL Server + /// + public class PostgresFixture : IAsyncLifetime + { + protected readonly string PostgresContainerName = $"postgresSqlServer-{Guid.NewGuid():N}"; + protected DockerClient Client; + + public PostgresFixture() + { + DockerClientConfiguration config; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + config = new DockerClientConfiguration(new Uri("unix://var/run/docker.sock")); + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + config = new DockerClientConfiguration(new Uri("npipe://./pipe/docker_engine")); + else + throw new NotSupportedException($"Unsupported OS [{RuntimeInformation.OSDescription}]"); + + Client = config.CreateClient(); + } + + protected string ImageName => "postgres"; + protected string Tag => "latest"; + + protected string PostgresImageName => $"{ImageName}:{Tag}"; + + public string ConnectionString { get; private set; } + + public async Task InitializeAsync() + { + var images = await Client.Images.ListImagesAsync(new ImagesListParameters + { + Filters = new Dictionary> + { + { + "reference", + new Dictionary + { + {PostgresImageName, true} + } + } + } + }); + + if (images.Count == 0) + await Client.Images.CreateImageAsync( + new ImagesCreateParameters { FromImage = ImageName, Tag = Tag }, null, + new Progress(message => + { + Console.WriteLine(!string.IsNullOrEmpty(message.ErrorMessage) + ? message.ErrorMessage + : $"{message.ID} {message.Status} {message.ProgressMessage}"); + })); + + var sqlServerHostPort = ThreadLocalRandom.Current.Next(9000, 10000); + + // create the container + await Client.Containers.CreateContainerAsync(new CreateContainerParameters + { + Image = PostgresImageName, + Name = PostgresContainerName, + Tty = true, + ExposedPorts = new Dictionary + { + {"5432/tcp", new EmptyStruct()} + }, + HostConfig = new HostConfig + { + PortBindings = new Dictionary> + { + { + "5432/tcp", + new List + { + new PortBinding + { + HostPort = $"{sqlServerHostPort}" + } + } + } + } + }, + Env = new[] + { + "POSTGRES_PASSWORD=postgres", + "POSTGRES_USER=postgres" + } + }); + + // start the container + await Client.Containers.StartContainerAsync(PostgresContainerName, new ContainerStartParameters()); + + // Provide a 10 second startup delay + await Task.Delay(TimeSpan.FromSeconds(10)); + + ConnectionString = $"Server=127.0.0.1;Port={sqlServerHostPort};" + + "Database=postgres;User Id=postgres;Password=postgres"; + } + + public async Task DisposeAsync() + { + if (Client != null) + { + await Client.Containers.StopContainerAsync(PostgresContainerName, new ContainerStopParameters()); + await Client.Containers.RemoveContainerAsync(PostgresContainerName, + new ContainerRemoveParameters { Force = true }); + Client.Dispose(); + } + } + } +} diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlAllEventsSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlAllEventsSpec.cs new file mode 100644 index 0000000..ef6b2e1 --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlAllEventsSpec.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2016 Lightbend Inc. +// Copyright (C) 2013-2016 Akka.NET project +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.Query; +using Akka.Persistence.Query.Sql; +using Akka.Persistence.TCK.Query; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Query +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlAllEventsSpec : AllEventsSpec + { + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" + akka.loglevel = INFO + akka.test.single-expect-default = 10s + akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" + akka.persistence.journal.postgresql {{ + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + auto-initialize = on + connection-string = ""{DbUtils.ConnectionString}"" + refresh-interval = 1s + }} + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); + } + + public PostgreSqlAllEventsSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlAllEventsSpec), output) + { + ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentAllEventsSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentAllEventsSpec.cs new file mode 100644 index 0000000..a7c7102 --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentAllEventsSpec.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2016 Lightbend Inc. +// Copyright (C) 2013-2016 Akka.NET project +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.Query; +using Akka.Persistence.Query.Sql; +using Akka.Persistence.TCK.Query; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Query +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlCurrentAllEventsSpec : AllEventsSpec + { + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" + akka.loglevel = INFO + akka.test.single-expect-default = 10s + akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" + akka.persistence.journal.postgresql {{ + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + auto-initialize = on + connection-string = ""{DbUtils.ConnectionString}"" + refresh-interval = 1s + }} + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); + } + + public PostgreSqlCurrentAllEventsSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlCurrentAllEventsSpec), output) + { + ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlAllPersistenceIdsSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentEventsByPersistenceIdSpec.cs similarity index 61% rename from src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlAllPersistenceIdsSpec.cs rename to src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentEventsByPersistenceIdSpec.cs index cb87f05..b635fe4 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlAllPersistenceIdsSpec.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentEventsByPersistenceIdSpec.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (C) 2009-2016 Lightbend Inc. // Copyright (C) 2013-2016 Akka.NET project // @@ -15,11 +15,15 @@ namespace Akka.Persistence.PostgreSql.Tests.Query { [Collection("PostgreSqlSpec")] - public class PostgreSqlAllPersistenceIdsSpec : PersistenceIdsSpec + public class PostgreSqlCurrentEventsByPersistenceIdSpec : CurrentEventsByPersistenceIdSpec { - public static Config SpecConfig => ConfigurationFactory.ParseString($@" + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" akka.loglevel = INFO - akka.test.single-expect-default = 10s akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" akka.persistence.journal.postgresql {{ class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" @@ -28,15 +32,15 @@ class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistenc auto-initialize = on connection-string = """ + DbUtils.ConnectionString + @""" refresh-interval = 1s - }}") - .WithFallback(SqlReadJournal.DefaultConfiguration()); - - static PostgreSqlAllPersistenceIdsSpec() - { - DbUtils.Initialize(); + }} + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); } - public PostgreSqlAllPersistenceIdsSpec(ITestOutputHelper output) : base(SpecConfig, nameof(PostgreSqlAllPersistenceIdsSpec), output) + public PostgreSqlCurrentEventsByPersistenceIdSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlCurrentEventsByPersistenceIdSpec), output) { ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); } diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentEventsByTagSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentEventsByTagSpec.cs new file mode 100644 index 0000000..ddede9e --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentEventsByTagSpec.cs @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2016 Lightbend Inc. +// Copyright (C) 2013-2016 Akka.NET project +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.Journal; +using Akka.Persistence.Query; +using Akka.Persistence.Query.Sql; +using Akka.Persistence.TCK.Query; +using System.Collections.Immutable; +using System.Linq; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Query +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlCurrentEventsByTagSpec : CurrentEventsByTagSpec + { + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" + akka.loglevel = INFO + akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" + akka.persistence.journal.postgresql {{ + event-adapters {{ + color-tagger = ""Akka.Persistence.TCK.Query.ColorFruitTagger, Akka.Persistence.TCK"" + }} + event-adapter-bindings = {{ + ""System.String"" = color-tagger + }} + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + auto-initialize = on + connection-string = """ + DbUtils.ConnectionString + @""" + refresh-interval = 1s + }} + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); + } + + public PostgreSqlCurrentEventsByTagSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlCurrentEventsByTagSpec), output) + { + ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentPersistenceIdsSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentPersistenceIdsSpec.cs new file mode 100644 index 0000000..7884a9e --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlCurrentPersistenceIdsSpec.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2016 Lightbend Inc. +// Copyright (C) 2013-2016 Akka.NET project +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.Query; +using Akka.Persistence.Query.Sql; +using Akka.Persistence.TCK.Query; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Query +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlCurrentPersistenceIdsSpec : CurrentPersistenceIdsSpec + { + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" + akka.loglevel = INFO + akka.test.single-expect-default = 10s + akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" + akka.persistence.journal.postgresql {{ + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + auto-initialize = on + connection-string = ""{DbUtils.ConnectionString}"" + refresh-interval = 1s + }} + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); + } + + public PostgreSqlCurrentPersistenceIdsSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlCurrentPersistenceIdsSpec), output) + { + ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByPersistenceIdSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByPersistenceIdSpec.cs index 9ed38be..ed58d4d 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByPersistenceIdSpec.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByPersistenceIdSpec.cs @@ -17,7 +17,12 @@ namespace Akka.Persistence.PostgreSql.Tests.Query [Collection("PostgreSqlSpec")] public class PostgreSqlEventsByPersistenceIdSpec : EventsByPersistenceIdSpec { - public static Config SpecConfig => ConfigurationFactory.ParseString($@" + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" akka.loglevel = INFO akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" akka.persistence.journal.postgresql {{ @@ -28,14 +33,14 @@ class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistenc connection-string = """ + DbUtils.ConnectionString + @""" refresh-interval = 1s }} - akka.test.single-expect-default = 10s"); - - static PostgreSqlEventsByPersistenceIdSpec() - { - DbUtils.Initialize(); + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); } - public PostgreSqlEventsByPersistenceIdSpec(ITestOutputHelper output) : base(SpecConfig, nameof(PostgreSqlEventsByPersistenceIdSpec), output) + public PostgreSqlEventsByPersistenceIdSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlEventsByPersistenceIdSpec), output) { ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); } diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByTagSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByTagSpec.cs index 65f963a..2750409 100644 --- a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByTagSpec.cs +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlEventsByTagSpec.cs @@ -6,12 +6,9 @@ //----------------------------------------------------------------------- using Akka.Configuration; -using Akka.Persistence.Journal; using Akka.Persistence.Query; using Akka.Persistence.Query.Sql; using Akka.Persistence.TCK.Query; -using System.Collections.Immutable; -using System.Linq; using Xunit; using Xunit.Abstractions; @@ -20,12 +17,17 @@ namespace Akka.Persistence.PostgreSql.Tests.Query [Collection("PostgreSqlSpec")] public class PostgreSqlEventsByTagSpec : EventsByTagSpec { - public static Config SpecConfig => ConfigurationFactory.ParseString($@" - akka.loglevel = DEBUG + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" + akka.loglevel = INFO akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" akka.persistence.journal.postgresql {{ event-adapters {{ - color-tagger = ""Akka.Persistence.PostgreSql.Tests.Query.ColorTagger, Akka.Persistence.PostgreSql.Tests"" + color-tagger = ""Akka.Persistence.TCK.Query.ColorFruitTagger, Akka.Persistence.TCK"" }} event-adapter-bindings = {{ ""System.String"" = color-tagger @@ -37,15 +39,15 @@ class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistenc connection-string = """ + DbUtils.ConnectionString + @""" refresh-interval = 1s }} - akka.test.single-expect-default = 10s"); - + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); - static PostgreSqlEventsByTagSpec() - { - DbUtils.Initialize(); } - public PostgreSqlEventsByTagSpec(ITestOutputHelper output) : base(SpecConfig, nameof(PostgreSqlEventsByTagSpec), output) + public PostgreSqlEventsByTagSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlEventsByTagSpec), output) { ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); } @@ -56,24 +58,4 @@ protected override void Dispose(bool disposing) DbUtils.Clean(); } } - - // This ColorTagger class was previously in Akka.Persistence.Sql.TestKit but has gone - public class ColorTagger : IWriteEventAdapter - { - public static readonly IImmutableSet Colors = ImmutableHashSet.CreateRange(new[] { "green", "black", "blue" }); - public string Manifest(object evt) => string.Empty; - - public object ToJournal(object evt) - { - var s = evt as string; - if (s != null) - { - var tags = Colors.Aggregate(ImmutableHashSet.Empty, (acc, color) => s.Contains(color) ? acc.Add(color) : acc); - return tags.IsEmpty - ? evt - : new Tagged(evt, tags); - } - else return evt; - } - } } \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlPersistenceIdsSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlPersistenceIdsSpec.cs new file mode 100644 index 0000000..e2ddb1d --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Query/PostgreSqlPersistenceIdsSpec.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2016 Lightbend Inc. +// Copyright (C) 2013-2016 Akka.NET project +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.Query; +using Akka.Persistence.Query.Sql; +using Akka.Persistence.TCK.Query; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Query +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlPersistenceIdsSpec : PersistenceIdsSpec + { + private static Config Initialize(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString($@" + akka.loglevel = INFO + akka.test.single-expect-default = 10s + akka.persistence.journal.plugin = ""akka.persistence.journal.postgresql"" + akka.persistence.journal.postgresql {{ + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + auto-initialize = on + connection-string = ""{DbUtils.ConnectionString}"" + refresh-interval = 1s + }} + akka.test.single-expect-default = 15s") + .WithFallback(PostgreSqlPersistence.DefaultConfiguration()) + .WithFallback(SqlReadJournal.DefaultConfiguration()) + .WithFallback(Persistence.DefaultConfig()); + } + + public PostgreSqlPersistenceIdsSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(Initialize(fixture), nameof(PostgreSqlPersistenceIdsSpec), output) + { + ReadJournal = Sys.ReadJournalFor(SqlReadJournal.Identifier); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DbUtils.Clean(); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/Serialization/PostgreSqlJournalSerializationSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Serialization/PostgreSqlJournalSerializationSpec.cs new file mode 100644 index 0000000..1742f22 --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Serialization/PostgreSqlJournalSerializationSpec.cs @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2021 Lightbend Inc. +// Copyright (C) 2013-2021 .NET Foundation +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.TCK.Serialization; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Serialization +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlJournalSerializationSpec : JournalSerializationSpec + { + public PostgreSqlJournalSerializationSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(CreateSpecConfig(fixture), "PostgreSqlJournalSerializationSpec", output) + { + } + + private static Config CreateSpecConfig(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString(@" + akka.persistence { + publish-plugin-commands = on + journal { + plugin = ""akka.persistence.journal.postgresql"" + postgresql { + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + schema-name = public + auto-initialize = on + connection-string = """ + DbUtils.ConnectionString + @""" + } + } + }"); + } + + [Fact(Skip = "Sql plugin does not support EventAdapter.Manifest")] + public override void Journal_should_serialize_Persistent_with_EventAdapter_manifest() + { + } + } +} diff --git a/src/Akka.Persistence.PostgreSql.Tests/Serialization/PostgreSqlSnapshotStoreSerializationSpec.cs b/src/Akka.Persistence.PostgreSql.Tests/Serialization/PostgreSqlSnapshotStoreSerializationSpec.cs new file mode 100644 index 0000000..c69deb8 --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/Serialization/PostgreSqlSnapshotStoreSerializationSpec.cs @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2021 Lightbend Inc. +// Copyright (C) 2013-2021 .NET Foundation +// +//----------------------------------------------------------------------- + +using Akka.Configuration; +using Akka.Persistence.TCK.Serialization; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.PostgreSql.Tests.Serialization +{ + [Collection("PostgreSqlSpec")] + public class PostgreSqlSnapshotStoreSerializationSpec : SnapshotStoreSerializationSpec + { + public PostgreSqlSnapshotStoreSerializationSpec(ITestOutputHelper output, PostgresFixture fixture) + : base(CreateSpecConfig(fixture), "PostgreSqlSnapshotStoreSerializationSpec", output) + { + } + + private static Config CreateSpecConfig(PostgresFixture fixture) + { + //need to make sure db is created before the tests start + DbUtils.Initialize(fixture); + + return ConfigurationFactory.ParseString(@" + akka.persistence { + publish-plugin-commands = on + journal { + plugin = ""akka.persistence.journal.postgresql"" + postgresql { + class = ""Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"" + plugin-dispatcher = ""akka.actor.default-dispatcher"" + table-name = event_journal + schema-name = public + auto-initialize = on + connection-string = """ + DbUtils.ConnectionString + @""" + } + } + }"); + } + } +} diff --git a/src/Akka.Persistence.PostgreSql.Tests/app.xml b/src/Akka.Persistence.PostgreSql.Tests/app.xml deleted file mode 100644 index c7c3fdf..0000000 --- a/src/Akka.Persistence.PostgreSql.Tests/app.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql.Tests/xunit.runner.json b/src/Akka.Persistence.PostgreSql.Tests/xunit.runner.json new file mode 100644 index 0000000..4a73b1e --- /dev/null +++ b/src/Akka.Persistence.PostgreSql.Tests/xunit.runner.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://xunit.github.io/schema/current/xunit.runner.schema.json", + "longRunningTestSeconds": 60, + "parallelizeAssembly": false, + "parallelizeTestCollections": false +} \ No newline at end of file diff --git a/src/Akka.Persistence.PostgreSql/Akka.Persistence.PostgreSql.csproj b/src/Akka.Persistence.PostgreSql/Akka.Persistence.PostgreSql.csproj index f24b62a..ad093d7 100644 --- a/src/Akka.Persistence.PostgreSql/Akka.Persistence.PostgreSql.csproj +++ b/src/Akka.Persistence.PostgreSql/Akka.Persistence.PostgreSql.csproj @@ -4,9 +4,8 @@ Akka.Persistence.PostgreSql Akka Persistence journal and snapshot store backed by PostgreSql database. - net45;netstandard1.6 + $(NetStandardLibVersion) true - 1.6.1 @@ -20,8 +19,8 @@ - - + + diff --git a/src/Akka.Persistence.PostgreSql/Journal/PostgreSqlQueryExecutor.cs b/src/Akka.Persistence.PostgreSql/Journal/PostgreSqlQueryExecutor.cs index dd030fc..ad2a14e 100644 --- a/src/Akka.Persistence.PostgreSql/Journal/PostgreSqlQueryExecutor.cs +++ b/src/Akka.Persistence.PostgreSql/Journal/PostgreSqlQueryExecutor.cs @@ -17,6 +17,7 @@ using System.Data; using System.Data.Common; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; namespace Akka.Persistence.PostgreSql.Journal @@ -60,20 +61,28 @@ public PostgreSqlQueryExecutor(PostgreSqlQueryConfiguration configuration, Akka. case StoredAsType.ByteA: _serialize = e => { - var serializer = Serialization.FindSerializerFor(e.Payload); - return new SerializationResult(NpgsqlDbType.Bytea, serializer.ToBinary(e.Payload), serializer); + var payloadType = e.Payload.GetType(); + var serializer = Serialization.FindSerializerForType(payloadType, Configuration.DefaultSerializer); + + // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811 + var binary = Akka.Serialization.Serialization.WithTransport(Serialization.System, () => serializer.ToBinary(e.Payload)); + + return new SerializationResult(NpgsqlDbType.Bytea, binary, serializer); }; - _deserialize = (type, serialized, manifest, serializerId) => + _deserialize = (type, payload, manifest, serializerId) => { if (serializerId.HasValue) { - return Serialization.Deserialize((byte[])serialized, serializerId.Value, manifest); + // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811 + return Serialization.Deserialize((byte[])payload, serializerId.Value, manifest); } else { // Support old writes that did not set the serializer id var deserializer = Serialization.FindSerializerForType(type, Configuration.DefaultSerializer); - return deserializer.FromBinary((byte[])serialized, type); + + // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811 + return Akka.Serialization.Serialization.WithTransport(Serialization.System, () => deserializer.FromBinary((byte[])payload, type)); } }; break; @@ -110,7 +119,7 @@ protected override void WriteEvent(DbCommand command, IPersistentRepresentation AddParameter(command, "@PersistenceId", DbType.String, e.PersistenceId); AddParameter(command, "@SequenceNr", DbType.Int64, e.SequenceNr); - AddParameter(command, "@Timestamp", DbType.Int64, TimestampProvider.GenerateTimestamp(e)); + AddParameter(command, "@Timestamp", DbType.Int64, e.Timestamp); AddParameter(command, "@IsDeleted", DbType.Boolean, false); AddParameter(command, "@Manifest", DbType.String, manifest); @@ -125,6 +134,15 @@ protected override void WriteEvent(DbCommand command, IPersistentRepresentation command.Parameters.Add(new NpgsqlParameter("@Payload", serializationResult.DbType) { Value = serializationResult.Payload }); + if (serializer != null) + { + AddParameter(command, "@SerializerId", DbType.Int32, serializer.Identifier); + } + else + { + AddParameter(command, "@SerializerId", DbType.Int32, DBNull.Value); + } + if (tags.Count != 0) { var tagBuilder = new StringBuilder(";", tags.Sum(x => x.Length) + tags.Count + 1); @@ -138,17 +156,15 @@ protected override void WriteEvent(DbCommand command, IPersistentRepresentation else AddParameter(command, "@Tag", DbType.String, DBNull.Value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static string QualifiedName(IPersistentRepresentation e) - { - var type = e.Payload.GetType(); - return type.TypeQualifiedName(); - } + => e.Payload.GetType().TypeQualifiedName(); protected override IPersistentRepresentation ReadEvent(DbDataReader reader) { var persistenceId = reader.GetString(PersistenceIdIndex); var sequenceNr = reader.GetInt64(SequenceNrIndex); - //var timestamp = reader.GetDateTime(TimestampIndex); + var timestamp = reader.GetInt64(TimestampIndex); var isDeleted = reader.GetBoolean(IsDeletedIndex); var manifest = reader.GetString(ManifestIndex); var raw = reader[PayloadIndex]; @@ -166,7 +182,7 @@ protected override IPersistentRepresentation ReadEvent(DbDataReader reader) var deserialized = _deserialize(type, raw, manifest, serializerId); - return new Persistent(deserialized, sequenceNr, persistenceId, manifest, isDeleted, ActorRefs.NoSender, null); + return new Persistent(deserialized, sequenceNr, persistenceId, manifest, isDeleted, ActorRefs.NoSender, null, timestamp); } } diff --git a/src/Akka.Persistence.PostgreSql/Snapshot/PostgreSqlQueryExecutor.cs b/src/Akka.Persistence.PostgreSql/Snapshot/PostgreSqlQueryExecutor.cs index 3ed4ad9..c0c4018 100644 --- a/src/Akka.Persistence.PostgreSql/Snapshot/PostgreSqlQueryExecutor.cs +++ b/src/Akka.Persistence.PostgreSql/Snapshot/PostgreSqlQueryExecutor.cs @@ -68,7 +68,10 @@ WITH upsert AS ( _serialize = ss => { var serializer = Serialization.FindSerializerFor(ss); - return new SerializationResult(NpgsqlDbType.Bytea, serializer.ToBinary(ss), serializer); + // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811 + var binary = Akka.Serialization.Serialization + .WithTransport(Serialization.System, () => serializer.ToBinary(ss)); + return new SerializationResult(NpgsqlDbType.Bytea, binary, serializer); }; _deserialize = (type, serialized, manifest, serializerId) => { @@ -116,10 +119,10 @@ protected override void SetManifestParameters(object snapshot, DbCommand command var snapshotType = snapshot.GetType(); var serializer = Serialization.FindSerializerForType(snapshotType, Configuration.DefaultSerializer); - string manifest = ""; - if (serializer is SerializerWithStringManifest) + var manifest = ""; + if (serializer is SerializerWithStringManifest stringManifest) { - manifest = ((SerializerWithStringManifest)serializer).Manifest(snapshot); + manifest = stringManifest.Manifest(snapshot); } else if (!serializer.IncludeManifest) { diff --git a/src/common.props b/src/common.props index d7d3c88..6b8707f 100644 --- a/src/common.props +++ b/src/common.props @@ -12,21 +12,16 @@ $(NoWarn);CS1591 - 2.3.1 + 2.4.1 + 2.4.3 + 1.4.16 + 5.0.3 + netstandard2.0 + net45 + 16.8.3 + netcoreapp3.1 + net471 - - - - - - 4.3.0 - - - - - 4.3.0 - - Upgraded for Akka.NET v1.3.9. Other Fixes and Improvements**