diff --git a/.github/workflows/gate.yml b/.github/workflows/gate.yml index 2b3f1a56..7297ea8b 100644 --- a/.github/workflows/gate.yml +++ b/.github/workflows/gate.yml @@ -19,34 +19,69 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v2 with: - dotnet-version: 6.0.x + dotnet-version: | + 3.1.x + 6.0.x - name: Install dependencies run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore - - name: Test - run: dotnet test --no-restore --verbosity normal /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov --logger "trx;LogFileName=results.trx" - - name: Publish NuGet artifacts - uses: actions/upload-artifact@v3 + + - name: Test (4.8) + run: dotnet test --no-restore --verbosity normal -f net48 --logger "trx;LogFileName=results4.trx" + - name: Generate unit test report (4.8) + uses: phoenix-actions/test-reporting@v8 + id: unit-test-report-win48 + if: success() || failure() with: - name: NuGet package - path: BitFaster.Caching/bin/Release/ - - name: Publish coverage report to coveralls.io + name: test results (win net4.8) + path: BitFaster.Caching.UnitTests/TestResults/results4.trx + reporter: dotnet-trx + only-summary: 'true' + + - name: Test (3.1) + run: dotnet test --no-restore --verbosity normal -f netcoreapp3.1 /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov --logger "trx;LogFileName=results3.trx" + - name: Generate unit test report (3.1) + uses: phoenix-actions/test-reporting@v8 + id: unit-test-report-win3 + if: success() || failure() + with: + name: test results (win net3.1) + path: BitFaster.Caching.UnitTests/TestResults/results3.trx + reporter: dotnet-trx + only-summary: 'true' + - name: Publish coverage report to coveralls.io (3.1) uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: BitFaster.Caching.UnitTests/TestResults/coverage.info - flag-name: win + path-to-lcov: BitFaster.Caching.UnitTests/TestResults/coverage.netcoreapp3.1.info + flag-name: win3 parallel: true - - name: Generate unit test report + + - name: Test (6.0) + run: dotnet test --no-restore --verbosity normal -f net6.0 /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov --logger "trx;LogFileName=results6.trx" + - name: Generate unit test report (6.0) uses: phoenix-actions/test-reporting@v8 - id: unit-test-report-win + id: unit-test-report-win6 if: success() || failure() with: - name: test results (win) - path: BitFaster.Caching.UnitTests/TestResults/results.trx + name: test results (win net6.0) + path: BitFaster.Caching.UnitTests/TestResults/results6.trx reporter: dotnet-trx only-summary: 'true' + - name: Publish coverage report to coveralls.io (6.0) + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: BitFaster.Caching.UnitTests/TestResults/coverage.net6.0.info + flag-name: win6 + parallel: true + + - name: Publish NuGet artifacts + uses: actions/upload-artifact@v3 + with: + name: NuGet package + path: BitFaster.Caching/bin/Release/ mac: @@ -66,12 +101,12 @@ jobs: - name: Build run: dotnet build --configuration Release --no-restore - name: Test - run: dotnet test --no-restore --verbosity normal /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov --logger "trx;LogFileName=results.trx" + run: dotnet test --no-restore --verbosity normal -f net6.0 /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov --logger "trx;LogFileName=results.trx" - name: Publish coverage report to coveralls.io uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: BitFaster.Caching.UnitTests/TestResults/coverage.info + path-to-lcov: BitFaster.Caching.UnitTests/TestResults/coverage.net6.0.info flag-name: mac parallel: true - name: Generate unit test report @@ -79,7 +114,7 @@ jobs: id: unit-test-report-mac if: success() || failure() with: - name: test results (mac) + name: test results (mac net6.0) path: BitFaster.Caching.UnitTests/TestResults/results.trx reporter: dotnet-trx only-summary: 'true' diff --git a/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj b/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj index c51d5124..e6f15cf6 100644 --- a/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj +++ b/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj @@ -1,7 +1,8 @@  - net6.0 + net48;netcoreapp3.1;net6.0 + 9.0 @@ -19,6 +20,10 @@ + + + + diff --git a/BitFaster.Caching.UnitTests/Intrinsics.cs b/BitFaster.Caching.UnitTests/Intrinsics.cs index e252a6cb..312d78a1 100644 --- a/BitFaster.Caching.UnitTests/Intrinsics.cs +++ b/BitFaster.Caching.UnitTests/Intrinsics.cs @@ -1,5 +1,6 @@ - +#if NETCOREAPP3_1_OR_GREATER using System.Runtime.Intrinsics.X86; +#endif using Xunit; namespace BitFaster.Caching.UnitTests @@ -8,8 +9,14 @@ public static class Intrinsics { public static void SkipAvxIfNotSupported() { +#if NETCOREAPP3_1_OR_GREATER // when we are trying to test Avx2, skip the test if it's not supported Skip.If(typeof(I) == typeof(DetectIsa) && !Avx2.IsSupported); +#else + Skip.If(true); +#endif } } } + + diff --git a/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs b/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs index bd6c99af..c240d395 100644 --- a/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs @@ -58,7 +58,7 @@ public async Task WhenItemIsExpiredItIsRemoved() { lru.GetOrAdd(1, valueFactory.Create); - await Task.Delay(timeToLive * ttlWaitMlutiplier); + await Task.Delay(timeToLive.MultiplyBy(ttlWaitMlutiplier)); lru.TryGet(1, out var value).Should().BeFalse(); } @@ -68,7 +68,7 @@ public async Task WhenItemIsUpdatedTtlIsExtended() { lru.GetOrAdd(1, valueFactory.Create); - await Task.Delay(timeToLive * ttlWaitMlutiplier); + await Task.Delay(timeToLive.MultiplyBy(ttlWaitMlutiplier)); lru.TryUpdate(1, "3"); @@ -134,7 +134,7 @@ public async Task WhenItemsAreExpiredExpireRemovesExpiredItems() lru.AddOrUpdate(8, "8"); lru.AddOrUpdate(9, "9"); - await Task.Delay(timeToLive * ttlWaitMlutiplier); + await Task.Delay(timeToLive.MultiplyBy(ttlWaitMlutiplier)); lru.Policy.ExpireAfterWrite.Value.TrimExpired(); @@ -152,7 +152,7 @@ public async Task WhenCacheHasExpiredAndFreshItemsExpireRemovesOnlyExpiredItems( lru.AddOrUpdate(5, "5"); lru.AddOrUpdate(6, "6"); - await Task.Delay(timeToLive * ttlWaitMlutiplier); + await Task.Delay(timeToLive.MultiplyBy(ttlWaitMlutiplier)); lru.GetOrAdd(1, valueFactory.Create); lru.GetOrAdd(2, valueFactory.Create); @@ -170,7 +170,7 @@ public async Task WhenItemsAreExpiredTrimRemovesExpiredItems() lru.AddOrUpdate(2, "2"); lru.AddOrUpdate(3, "3"); - await Task.Delay(timeToLive * ttlWaitMlutiplier); + await Task.Delay(timeToLive.MultiplyBy(ttlWaitMlutiplier)); lru.Policy.Eviction.Value.Trim(1); diff --git a/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs b/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs index be296238..188c15b3 100644 --- a/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs @@ -47,7 +47,7 @@ public async Task WhenItemsAreExpiredExpireRemovesExpiredItems() lru.AddOrUpdate(2, "2"); lru.AddOrUpdate(3, "3"); - await Task.Delay(ttl * 2); + await Task.Delay(ttl.MultiplyBy(2)); lru.Policy.ExpireAfterWrite.Value.TrimExpired(); diff --git a/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs b/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs index 845a8f94..54e1fe7d 100644 --- a/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs +++ b/BitFaster.Caching.UnitTests/Lru/TLruTickCount64PolicyTests .cs @@ -1,4 +1,6 @@ -using FluentAssertions; +#if NETCOREAPP3_1_OR_GREATER + +using FluentAssertions; using FluentAssertions.Extensions; using BitFaster.Caching.Lru; using System; @@ -157,3 +159,5 @@ private LongTickCountLruItem CreateItem(bool wasAccessed, bool isExpir } } } + +#endif diff --git a/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs b/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs index 08e7d1c9..e1938a8c 100644 --- a/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs +++ b/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using BitFaster.Caching.Scheduler; @@ -36,8 +33,8 @@ public async Task WhenWorkIsScheduledItIsRun() { bool run = false; - TaskCompletionSource tcs = new TaskCompletionSource(); - scheduler.Run(() => { Volatile.Write(ref run, true); tcs.SetResult(); }); + var tcs = new TaskCompletionSource(); + scheduler.Run(() => { Volatile.Write(ref run, true); tcs.SetResult(true); }); await tcs.Task; Volatile.Read(ref run).Should().BeTrue(); @@ -58,8 +55,8 @@ public async Task WhenWorkDoesNotThrowLastExceptionIsEmpty() [Fact] public async Task WhenWorkThrowsLastExceptionIsPopulated() { - TaskCompletionSource tcs = new TaskCompletionSource(); - scheduler.Run(() => { tcs.SetResult(); throw new InvalidCastException(); }); + var tcs = new TaskCompletionSource(); + scheduler.Run(() => { tcs.SetResult(true); throw new InvalidCastException(); }); await tcs.Task; await scheduler.WaitForExceptionAsync(); @@ -71,14 +68,14 @@ public async Task WhenWorkThrowsLastExceptionIsPopulated() [Fact] public void WhenBacklogExceededTasksAreDropped() { - TaskCompletionSource tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); for (int i = 0; i < BackgroundThreadScheduler.MaxBacklog * 2; i++) { scheduler.Run(() => { tcs.Task.Wait(); }); } - tcs.SetResult(); + tcs.SetResult(true); scheduler.RunCount.Should().BeCloseTo(BackgroundThreadScheduler.MaxBacklog, 1); } diff --git a/BitFaster.Caching.UnitTests/Scheduler/ThreadPoolSchedulerTests.cs b/BitFaster.Caching.UnitTests/Scheduler/ThreadPoolSchedulerTests.cs index 57bb20b1..8dfa8cce 100644 --- a/BitFaster.Caching.UnitTests/Scheduler/ThreadPoolSchedulerTests.cs +++ b/BitFaster.Caching.UnitTests/Scheduler/ThreadPoolSchedulerTests.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using BitFaster.Caching.Scheduler; @@ -30,8 +27,8 @@ public async Task WhenWorkIsScheduledItIsRun() { bool run = false; - TaskCompletionSource tcs = new TaskCompletionSource(); - scheduler.Run(() => { Volatile.Write(ref run, true); tcs.SetResult(); }); + var tcs = new TaskCompletionSource(); + scheduler.Run(() => { Volatile.Write(ref run, true); tcs.SetResult(true); }); await tcs.Task; @@ -41,10 +38,10 @@ public async Task WhenWorkIsScheduledItIsRun() [Fact] public async Task WhenWorkDoesNotThrowLastExceptionIsEmpty() { - TaskCompletionSource tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); scheduler.RunCount.Should().Be(0); - scheduler.Run(() => { tcs.SetResult(); }); + scheduler.Run(() => { tcs.SetResult(true); }); await tcs.Task; @@ -54,9 +51,9 @@ public async Task WhenWorkDoesNotThrowLastExceptionIsEmpty() [Fact] public async Task WhenWorkThrowsLastExceptionIsPopulated() { - TaskCompletionSource tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); scheduler.Run(() => { throw new InvalidCastException(); }); - scheduler.Run(() => { tcs.SetResult(); }); + scheduler.Run(() => { tcs.SetResult(true); }); await tcs.Task; await scheduler.WaitForExceptionAsync(); diff --git a/BitFaster.Caching.UnitTests/TimeSpanExtensions.cs b/BitFaster.Caching.UnitTests/TimeSpanExtensions.cs new file mode 100644 index 00000000..df848cb3 --- /dev/null +++ b/BitFaster.Caching.UnitTests/TimeSpanExtensions.cs @@ -0,0 +1,13 @@ +using System; + +namespace BitFaster.Caching.UnitTests +{ + internal static class TimeSpanExtensions + { + // .NET Framework has no TimeSpan operator* + public static TimeSpan MultiplyBy(this TimeSpan multiplicand, int multiplier) + { + return TimeSpan.FromTicks(multiplicand.Ticks * multiplier); + } + } +}