Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Resolve IAsyncCommand / IAsyncValueValueCommand Unit Test Race Condition #1076

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ccb4cc1
Add Unit Test Timeouts
TheCodeTraveler Mar 14, 2021
29462af
Add macOS Unit Tests
TheCodeTraveler Mar 14, 2021
7fed573
Build 'samples/XCT.Sample.sln' on macOS
TheCodeTraveler Mar 14, 2021
4562be1
Restore Unit Test NuGet Packages
TheCodeTraveler Mar 14, 2021
bc9b568
Fix YAML formatting
TheCodeTraveler Mar 14, 2021
00bfc09
Add xunit.runner.console
TheCodeTraveler Mar 14, 2021
524bc50
Use latest stable version of Microsoft.NET.Test.Sdk
TheCodeTraveler Mar 14, 2021
d2eee34
Fix Unit Tests on macos
TheCodeTraveler Mar 14, 2021
768a382
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
9ab41ec
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
28db359
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
6875865
Add SemaphoreSlim
TheCodeTraveler Mar 14, 2021
e95b738
Add `dotnet restore`
TheCodeTraveler Mar 14, 2021
a776a19
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
a2cff28
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
1b1170d
Revert "Add SemaphoreSlim"
TheCodeTraveler Mar 14, 2021
8aafba6
Revert BaseCommand.semaphoreSlim
TheCodeTraveler Mar 14, 2021
90a4a57
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
a90ab0c
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
4e9b25a
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
596baf1
Add ConfigureAwait(false) to ValueTaskDelay(int)
TheCodeTraveler Mar 14, 2021
90c3c97
Change Platform from NetCore to macOS
TheCodeTraveler Mar 14, 2021
af4e8db
Passthrough ValueTask
TheCodeTraveler Mar 14, 2021
d7b2842
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
1a7c7fb
Revert "Update azure-pipelines.yml"
TheCodeTraveler Mar 14, 2021
b9f9220
Use ConfigureAwait(false)
TheCodeTraveler Mar 14, 2021
01ea4a9
Rename Task
TheCodeTraveler Mar 14, 2021
654db18
Remove `static`
TheCodeTraveler Mar 14, 2021
a86522a
Remove `static`
TheCodeTraveler Mar 14, 2021
c9224b6
Revert p:BuildInParallel=false
TheCodeTraveler Mar 14, 2021
bf93f0c
Update azure-pipelines.yml
TheCodeTraveler Mar 14, 2021
031121a
Revert "Update azure-pipelines.yml"
TheCodeTraveler Mar 14, 2021
458feb2
Revert "Revert "Update azure-pipelines.yml""
TheCodeTraveler Mar 14, 2021
38fc6ff
Revert "Revert "Revert "Update azure-pipelines.yml"""
TheCodeTraveler Mar 14, 2021
e36f8f5
Merge branch 'develop' into Fix-AsyncCommand-Unit-Test-Race-Conditions
TheCodeTraveler Mar 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ variables:
NETCORE_TEST_VERSION_3_1: '3.1.x'
NETCORE_TEST_VERSION_2_1: '2.1.x'
RunPoliCheck: 'false'
PathToCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj'
PathToMarkupCsproj: 'src/Markup/Xamarin.CommunityToolkit.Markup/Xamarin.CommunityToolkit.Markup.csproj'
PathToCommunityToolkitCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj'
PathToSamplesSln: 'samples/XCT.Sample.sln'
PathToUnitTestCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Xamarin.CommunityToolkit.UnitTests.csproj'
PathToMsBuildOnMacOS: 'mono /Applications/Visual\ studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/MSBuild.dll'
PathToSln: 'samples/XCT.Sample.sln'

resources:
Expand Down Expand Up @@ -95,9 +97,9 @@ jobs:
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/')
# restore, build and pack the packages
- task: MSBuild@1
displayName: Build Solution
displayName: Build Xamarin.CommunityToolkit.csproj
inputs:
solution: $(PathToCsproj)
solution: $(PathToCommunityToolkitCsproj)
configuration: Release
msbuildArguments: '/restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false'
- task: CopyFiles@2
Expand All @@ -107,7 +109,7 @@ jobs:
- task: MSBuild@1
displayName: Pack NuGets
inputs:
solution: $(PathToCsproj)
solution: $(PathToCommunityToolkitCsproj)
configuration: Release
msbuildArguments: '/t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"'
- task: MSBuild@1
Expand Down Expand Up @@ -191,13 +193,29 @@ jobs:
version: $(NETCORE_TEST_VERSION_2_1)
includePreviewVersions: false
- task: CmdLine@2
displayName: 'Build Solution'
displayName: 'Build Xamarin.CommunityToolkit.csproj'
inputs:
script: '$(PathToMsBuildOnMacOS) $(PathToCommunityToolkitCsproj) /p:Configuration=Release /restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false'
- task: CmdLine@2
displayName: 'Run Unit Tests'
inputs:
script: 'mono /Applications/Visual\ studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/MSBuild.dll $(PathToCsproj) /p:Configuration=Release /restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false'
script: |
dotnet restore $(PathToUnitTestCsproj) /p:Configuration=Release
$(PathToMsBuildOnMacOS) $(PathToUnitTestCsproj) /p:Configuration=Release /restore /t:Build

echo "********** Running Unit Tests on .NET Framework (xUnit does not support dotnet test for .NET Framework: https://xunit.net/docs/getting-started/netfx/cmdline) **********"

# UnitTestDLL for .NET Framework 4.6.1 Result: `find . -name Xamarin.CommunityToolkit.UnitTests.dll | grep bin | grep 461`
# XUnit Console Runner for .NET Framework 4.6.1 Result: `find ~/.nuget/packages | grep net461 | grep xunit.console.exe | grep -v config`

mono "`find ~/.nuget/packages | grep net461 | grep xunit.console.exe | grep -v config`" "`find . -name Xamarin.CommunityToolkit.UnitTests.dll | grep bin | grep 461`"

echo "***** Running Unit Tests on .NET Core *****"
dotnet test $(PathToUnitTestCsproj) /p:Configuration=Release /p:Platform="macOS"
- task: CmdLine@2
displayName: 'Pack NuGets'
inputs:
script: 'mono /Applications/Visual\ studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/MSBuild.dll $(PathToCsproj) /p:Configuration=Release /t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"'
script: '$(PathToMsBuildOnMacOS) $(PathToCommunityToolkitCsproj) /p:Configuration=Release /t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"'

- ${{ if eq(variables['System.TeamProject'], 'devdiv') }}:
- template: sign-artifacts/jobs/v2.yml@internal-templates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ public void LocalizedStringTests_WeekSubscribe_ValidImplementation()
Assert.True(isTrigered);
}

#if NET461
#warning Test fails on mono x64 Running on macOS
#else
[Fact]
public void LocalizedStringTests_Disposed_IfNoReferences()
{
Expand All @@ -97,5 +100,6 @@ void SetLocalizedString()
localizedString = new LocalizedString(localizationManager, () => localizationManager[testString]);
}
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public void AsyncCommand_NoParameter_NoCanExecute_Test()
Assert.True(command.CanExecute(null));
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_MainThreadExecution_Test()
{
// Arrange
Expand Down Expand Up @@ -213,7 +213,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public Task AsyncCommand_RaiseCanExecuteChanged_BackgroundThreadCreation_BackgroundThreadExecution_Test() => Task.Run(async () =>
{
// Arrange
Expand Down Expand Up @@ -267,7 +267,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
});

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_BackgroundThreadExecution_Test()
{
// Arrange
Expand Down Expand Up @@ -322,7 +322,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncCommand_RaiseCanExecuteChanged_BackgroundThreadCreation_MainThreadExecution_Test()
{
// Arrange
Expand Down Expand Up @@ -380,7 +380,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncCommand_ChangeCanExecute_Test()
{
// Arrange
Expand Down Expand Up @@ -429,7 +429,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncCommand_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -459,7 +459,7 @@ public async Task AsyncCommand_CanExecuteChanged_AllowsMultipleExecutions_Test()
void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncCommand_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public void IAsyncCommand_NoParameter_CanExecuteFalse_NoParameter_Test()
Assert.False(command.CanExecute(null));
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task IAsyncCommand_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -207,7 +207,7 @@ public async Task IAsyncCommand_CanExecuteChanged_AllowsMultipleExecutions_Test(
void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task IAsyncCommand_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public void ICommand_Parameter_CanExecuteChanged_Test()
Assert.False(command.CanExecute(false));
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_Parameter_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -218,7 +218,7 @@ public async Task ICommand_Parameter_CanExecuteChanged_AllowsMultipleExecutions_
command.CanExecuteChanged -= handleCanExecuteChanged;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_Parameter_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -263,7 +263,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_NoParameter_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -291,7 +291,7 @@ public async Task ICommand_NoParameter_CanExecuteChanged_AllowsMultipleExecution
command.CanExecuteChanged -= handleCanExecuteChanged;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_NoParameter_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public void AsyncValueCommandNoParameter_NoCanExecute_Test()
Assert.True(command.CanExecute(null));
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncValueCommand_RaiseCanExecuteChanged_Test()
{
// Arrange
Expand Down Expand Up @@ -236,7 +236,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncValueCommand_ChangeCanExecute_Test()
{
// Arrange
Expand Down Expand Up @@ -285,7 +285,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
}
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncValueCommand_Parameter_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -315,7 +315,7 @@ public async Task AsyncValueCommand_Parameter_CanExecuteChanged_AllowsMultipleEx
command.CanExecuteChanged -= handleCanExecuteChanged;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncValueCommand_Parameter_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -363,7 +363,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
Assert.Equal(canExecuteChangedCount, handleCanExecuteChangedResult);
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncValueCommand_NoParameter_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -393,7 +393,7 @@ public async Task AsyncValueCommand_NoParameter_CanExecuteChanged_AllowsMultiple
command.CanExecuteChanged -= handleCanExecuteChanged;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task AsyncValueCommand_NoParameter_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ public abstract class BaseAsyncValueCommandTests : BaseCommandTests

protected new ValueTask ParameterImmediateNullReferenceExceptionTask(int delay) => throw new NullReferenceException();

protected async ValueTask ValueTaskDelay(int delay) => await Task.Delay(delay);

protected new async ValueTask NoParameterDelayedNullReferenceExceptionTask()
{
await Task.Delay(Delay);
Expand All @@ -28,5 +26,7 @@ public abstract class BaseAsyncValueCommandTests : BaseCommandTests
await Task.Delay(delay);
throw new NullReferenceException();
}

ValueTask ValueTaskDelay(int delay) => new ValueTask(Task.Delay(delay));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ public void ICommand_Parameter_CanExecuteChanged_Test()
Assert.False(command.CanExecute(false));
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_Parameter_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand All @@ -243,7 +243,7 @@ public async Task ICommand_Parameter_CanExecuteChanged_AllowsMultipleExecutions_
command.CanExecuteChanged -= handleCanExecuteChanged;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_Parameter_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -287,7 +287,7 @@ async void handleCanExecuteChanged(object? sender, EventArgs e)
Assert.Equal(canExecuteChangedCount, handleCanExecuteChangedResult);
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_NoParameter_CanExecuteChanged_AllowsMultipleExecutions_Test()
{
// Arrange
Expand Down Expand Up @@ -315,7 +315,7 @@ public async Task ICommand_NoParameter_CanExecuteChanged_AllowsMultipleExecution
command.CanExecuteChanged -= handleCanExecuteChanged;
}

[Fact]
[Fact(Timeout = ICommandTestTimeout)]
public async Task ICommand_NoParameter_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test()
{
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.ObjectModel.ICommandTests
[Collection(nameof(BaseCommandTests))]
public abstract class BaseCommandTests
{
public const int ICommandTestTimeout = Delay * 6;
public const int Delay = 500;

public BaseCommandTests() => Device.PlatformServices = new MockPlatformServices();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='macOS'">
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup Condition="'$(Platform)'!='macOS'">
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net461</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<PackageReference Include="NSubstitute" Version="4.2.2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
Expand All @@ -17,6 +22,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="xunit.runner.console" Version="2.4.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ namespace Xamarin.CommunityToolkit.ObjectModel.Internals
{
public abstract partial class BaseCommand<TCanExecute>
{
static readonly Thread mainThread = Thread.CurrentThread;
readonly SynchronizationContext? synchronizationContext = SynchronizationContext.Current;

static bool IsMainThread => Thread.CurrentThread == mainThread;
bool IsMainThread => SynchronizationContext.Current == synchronizationContext;

static void BeginInvokeOnMainThread(Action action)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ namespace Xamarin.CommunityToolkit.ObjectModel.Internals
{
public abstract partial class BaseCommand<TCanExecute>
{
static readonly SynchronizationContext? synchronizationContext = SynchronizationContext.Current;
readonly SynchronizationContext? synchronizationContext = SynchronizationContext.Current;

static bool IsMainThread => SynchronizationContext.Current == synchronizationContext;
bool IsMainThread => SynchronizationContext.Current == synchronizationContext;

static void BeginInvokeOnMainThread(Action action)
void BeginInvokeOnMainThread(Action action)
{
if (synchronizationContext != null && SynchronizationContext.Current != synchronizationContext)
synchronizationContext.Post(_ => action(), null);
Expand Down