зеркало из https://github.com/dotnet/extensions.git
Merge branch 'main' into xakep139/log-source-gen-WPF-bug
This commit is contained in:
Коммит
10283f004d
|
@ -170,13 +170,13 @@
|
|||
</Dependency>
|
||||
</ProductDependencies>
|
||||
<ToolsetDependencies>
|
||||
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.24225.1">
|
||||
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.24266.3">
|
||||
<Uri>https://github.com/dotnet/arcade</Uri>
|
||||
<Sha>67d23f4ba1813b315e7e33c71d18b63475f5c5f8</Sha>
|
||||
<Sha>e6f70c7dd528f05cd28cec2a179d58c22e91d9ac</Sha>
|
||||
</Dependency>
|
||||
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="8.0.0-beta.24225.1">
|
||||
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="8.0.0-beta.24266.3">
|
||||
<Uri>https://github.com/dotnet/arcade</Uri>
|
||||
<Sha>67d23f4ba1813b315e7e33c71d18b63475f5c5f8</Sha>
|
||||
<Sha>e6f70c7dd528f05cd28cec2a179d58c22e91d9ac</Sha>
|
||||
</Dependency>
|
||||
</ToolsetDependencies>
|
||||
</Dependencies>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
parameters:
|
||||
runAsPublic: false
|
||||
sourceIndexPackageVersion: 1.0.1-20230228.2
|
||||
sourceIndexUploadPackageVersion: 2.0.0-20240502.12
|
||||
sourceIndexProcessBinlogPackageVersion: 1.0.1-20240129.2
|
||||
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
|
||||
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
|
||||
preSteps: []
|
||||
|
@ -14,15 +15,15 @@ jobs:
|
|||
dependsOn: ${{ parameters.dependsOn }}
|
||||
condition: ${{ parameters.condition }}
|
||||
variables:
|
||||
- name: SourceIndexPackageVersion
|
||||
value: ${{ parameters.sourceIndexPackageVersion }}
|
||||
- name: SourceIndexUploadPackageVersion
|
||||
value: ${{ parameters.sourceIndexUploadPackageVersion }}
|
||||
- name: SourceIndexProcessBinlogPackageVersion
|
||||
value: ${{ parameters.sourceIndexProcessBinlogPackageVersion }}
|
||||
- name: SourceIndexPackageSource
|
||||
value: ${{ parameters.sourceIndexPackageSource }}
|
||||
- name: BinlogPath
|
||||
value: ${{ parameters.binlogPath }}
|
||||
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
|
||||
- group: source-dot-net stage1 variables
|
||||
- template: /eng/common/templates-official/variables/pool-providers.yml
|
||||
- template: /eng/common/templates/variables/pool-providers.yml
|
||||
|
||||
${{ if ne(parameters.pool, '') }}:
|
||||
pool: ${{ parameters.pool }}
|
||||
|
@ -33,24 +34,23 @@ jobs:
|
|||
demands: ImageOverride -equals windows.vs2019.amd64.open
|
||||
${{ if eq(variables['System.TeamProject'], 'internal') }}:
|
||||
name: $(DncEngInternalBuildPool)
|
||||
image: windows.vs2022.amd64
|
||||
os: windows
|
||||
demands: ImageOverride -equals windows.vs2019.amd64
|
||||
|
||||
steps:
|
||||
- ${{ each preStep in parameters.preSteps }}:
|
||||
- ${{ preStep }}
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: Use .NET Core SDK 6
|
||||
displayName: Use .NET 8 SDK
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: 6.0.x
|
||||
version: 8.0.x
|
||||
installationPath: $(Agent.TempDirectory)/dotnet
|
||||
workingDirectory: $(Agent.TempDirectory)
|
||||
|
||||
- script: |
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(sourceIndexProcessBinlogPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(sourceIndexUploadPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
displayName: Download Tools
|
||||
# Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
|
||||
workingDirectory: $(Agent.TempDirectory)
|
||||
|
@ -62,7 +62,24 @@ jobs:
|
|||
displayName: Process Binlog into indexable sln
|
||||
|
||||
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
|
||||
- script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
|
||||
displayName: Upload stage1 artifacts to source index
|
||||
env:
|
||||
BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
|
||||
- task: AzureCLI@2
|
||||
displayName: Get stage 1 auth token
|
||||
inputs:
|
||||
azureSubscription: 'SourceDotNet Stage1 Publish'
|
||||
addSpnToEnvironment: true
|
||||
scriptType: 'ps'
|
||||
scriptLocation: 'inlineScript'
|
||||
inlineScript: |
|
||||
echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$env:servicePrincipalId"
|
||||
echo "##vso[task.setvariable variable=ARM_ID_TOKEN]$env:idToken"
|
||||
echo "##vso[task.setvariable variable=ARM_TENANT_ID]$env:tenantId"
|
||||
|
||||
- script: |
|
||||
echo "Client ID: $(ARM_CLIENT_ID)"
|
||||
echo "ID Token: $(ARM_ID_TOKEN)"
|
||||
echo "Tenant ID: $(ARM_TENANT_ID)"
|
||||
az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN)
|
||||
displayName: "Login to Azure"
|
||||
|
||||
- script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1
|
||||
displayName: Upload stage1 artifacts to source index
|
|
@ -1,6 +1,7 @@
|
|||
parameters:
|
||||
runAsPublic: false
|
||||
sourceIndexPackageVersion: 1.0.1-20230228.2
|
||||
sourceIndexUploadPackageVersion: 2.0.0-20240502.12
|
||||
sourceIndexProcessBinlogPackageVersion: 1.0.1-20240129.2
|
||||
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
|
||||
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
|
||||
preSteps: []
|
||||
|
@ -14,14 +15,14 @@ jobs:
|
|||
dependsOn: ${{ parameters.dependsOn }}
|
||||
condition: ${{ parameters.condition }}
|
||||
variables:
|
||||
- name: SourceIndexPackageVersion
|
||||
value: ${{ parameters.sourceIndexPackageVersion }}
|
||||
- name: SourceIndexUploadPackageVersion
|
||||
value: ${{ parameters.sourceIndexUploadPackageVersion }}
|
||||
- name: SourceIndexProcessBinlogPackageVersion
|
||||
value: ${{ parameters.sourceIndexProcessBinlogPackageVersion }}
|
||||
- name: SourceIndexPackageSource
|
||||
value: ${{ parameters.sourceIndexPackageSource }}
|
||||
- name: BinlogPath
|
||||
value: ${{ parameters.binlogPath }}
|
||||
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
|
||||
- group: source-dot-net stage1 variables
|
||||
- template: /eng/common/templates/variables/pool-providers.yml
|
||||
|
||||
${{ if ne(parameters.pool, '') }}:
|
||||
|
@ -40,16 +41,16 @@ jobs:
|
|||
- ${{ preStep }}
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: Use .NET Core SDK 6
|
||||
displayName: Use .NET 8 SDK
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: 6.0.x
|
||||
version: 8.0.x
|
||||
installationPath: $(Agent.TempDirectory)/dotnet
|
||||
workingDirectory: $(Agent.TempDirectory)
|
||||
|
||||
- script: |
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(sourceIndexProcessBinlogPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
$(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(sourceIndexUploadPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
|
||||
displayName: Download Tools
|
||||
# Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
|
||||
workingDirectory: $(Agent.TempDirectory)
|
||||
|
@ -61,7 +62,24 @@ jobs:
|
|||
displayName: Process Binlog into indexable sln
|
||||
|
||||
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
|
||||
- script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
|
||||
displayName: Upload stage1 artifacts to source index
|
||||
env:
|
||||
BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
|
||||
- task: AzureCLI@2
|
||||
displayName: Get stage 1 auth token
|
||||
inputs:
|
||||
azureSubscription: 'SourceDotNet Stage1 Publish'
|
||||
addSpnToEnvironment: true
|
||||
scriptType: 'ps'
|
||||
scriptLocation: 'inlineScript'
|
||||
inlineScript: |
|
||||
echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$env:servicePrincipalId"
|
||||
echo "##vso[task.setvariable variable=ARM_ID_TOKEN]$env:idToken"
|
||||
echo "##vso[task.setvariable variable=ARM_TENANT_ID]$env:tenantId"
|
||||
|
||||
- script: |
|
||||
echo "Client ID: $(ARM_CLIENT_ID)"
|
||||
echo "ID Token: $(ARM_ID_TOKEN)"
|
||||
echo "Tenant ID: $(ARM_TENANT_ID)"
|
||||
az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN)
|
||||
displayName: "Login to Azure"
|
||||
|
||||
- script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1
|
||||
displayName: Upload stage1 artifacts to source index
|
|
@ -51,7 +51,6 @@
|
|||
<PackageVersion Include="System.IO.Hashing" Version="$(SystemIOHashingVersion)" />
|
||||
<PackageVersion Include="System.Memory" Version="4.5.5" />
|
||||
<PackageVersion Include="System.Net.Http.Json" Version="$(SystemNetHttpJsonVersion)" />
|
||||
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
||||
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
<PackageVersion Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"msbuild-sdks": {
|
||||
"Microsoft.Build.NoTargets": "3.7.0",
|
||||
"Microsoft.Build.Traversal": "3.2.0",
|
||||
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24225.1",
|
||||
"Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24225.1"
|
||||
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24266.3",
|
||||
"Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24266.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
<PackageReference Include="Microsoft.Bcl.TimeProvider" Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" />
|
||||
<PackageReference Include="System.Collections.Immutable" Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))" />
|
||||
<Reference Include="System.Net.Http" Condition="'$(TargetFramework)' == 'net462'" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -42,6 +42,102 @@ timeProvider.Advance(TimeSpan.FromSeconds(5));
|
|||
myComponent.CheckState();
|
||||
```
|
||||
|
||||
## Use ConfigureAwait(true) with FakeTimeProvider.Advance
|
||||
|
||||
The Advance method is used to simulate the passage of time. This can be useful in tests where you need to control the timing of asynchronous operations.
|
||||
When awaiting a task in a test that uses `FakeTimeProvider`, it's important to use `ConfigureAwait(true)`.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```cs
|
||||
await provider.Delay(TimeSpan.FromSeconds(delay)).ConfigureAwait(true);
|
||||
```
|
||||
|
||||
This ensures that the continuation of the awaited task (i.e., the code that comes after the await statement) runs in the original context.
|
||||
|
||||
For a more realistic example, consider the following test using Polly:
|
||||
|
||||
```cs
|
||||
using Polly;
|
||||
using Polly.Retry;
|
||||
|
||||
public class SomeService(TimeProvider timeProvider)
|
||||
{
|
||||
// Don't do this in real life, not thread safe
|
||||
public int Tries { get; private set; }
|
||||
|
||||
private readonly ResiliencePipeline _retryPipeline = new ResiliencePipelineBuilder { TimeProvider = timeProvider }
|
||||
.AddRetry(
|
||||
new RetryStrategyOptions
|
||||
{
|
||||
ShouldHandle = new PredicateBuilder().Handle<InvalidOperationException>(),
|
||||
Delay = TimeSpan.FromSeconds(1),
|
||||
MaxRetryAttempts = 2,
|
||||
BackoffType = DelayBackoffType.Linear,
|
||||
})
|
||||
.Build();
|
||||
|
||||
public async Task<int> PollyRetry(double taskDelay, double cancellationSeconds)
|
||||
{
|
||||
CancellationTokenSource cts = new(TimeSpan.FromSeconds(cancellationSeconds), timeProvider);
|
||||
Tries = 0;
|
||||
|
||||
// get a context from the pool and return it when done
|
||||
var context = ResilienceContextPool.Shared.Get(
|
||||
// ensure execution continues on captured context
|
||||
continueOnCapturedContext: true,
|
||||
cancellationToken: cts.Token);
|
||||
|
||||
var result = await _retryPipeline.ExecuteAsync(
|
||||
async _ =>
|
||||
{
|
||||
Tries++;
|
||||
|
||||
// Simulate a task that takes some time to complete
|
||||
await Task.Delay(TimeSpan.FromSeconds(taskDelay), timeProvider).ConfigureAwait(true);
|
||||
|
||||
if (Tries <= 2)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return Tries;
|
||||
},
|
||||
context);
|
||||
|
||||
ResilienceContextPool.Shared.Return(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
|
||||
public class SomeServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void PollyRetry_ShouldHave2Tries()
|
||||
{
|
||||
var timeProvider = new FakeTimeProvider();
|
||||
var someService = new SomeService(timeProvider);
|
||||
|
||||
// Act
|
||||
var result = someService.PollyRetry(taskDelay: 1, cancellationSeconds: 6);
|
||||
|
||||
// Advancing the time more than one second should resolves the first execution delay.
|
||||
timeProvider.Advance(TimeSpan.FromMilliseconds(1001));
|
||||
|
||||
// Advancing the time more than the retry delay time of 1s,
|
||||
// and less then the task execution delay should start the second try
|
||||
timeProvider.Advance(TimeSpan.FromMilliseconds(1050));
|
||||
|
||||
// Assert
|
||||
result.IsCompleted.Should().BeFalse();
|
||||
someService.Tries.Should().Be(2);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Feedback & Contributing
|
||||
|
||||
We welcome feedback and contributions in [our GitHub repo](https://github.com/dotnet/extensions).
|
||||
|
|
|
@ -381,4 +381,57 @@ public class FakeTimeProviderTests
|
|||
// Assert
|
||||
Assert.Single(calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimulateRetryPolicy()
|
||||
{
|
||||
// Arrange
|
||||
var retries = 42;
|
||||
var tries = 0;
|
||||
var taskDelay = 0.5;
|
||||
var delay = 1;
|
||||
var provider = new FakeTimeProvider();
|
||||
|
||||
async Task<int> simulatedPollyRetry()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// simulate task that takes some time to complete
|
||||
await provider.Delay(TimeSpan.FromSeconds(taskDelay));
|
||||
tries++;
|
||||
|
||||
if (tries <= retries)
|
||||
{
|
||||
// the task failed, trigger retry
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return tries;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// ConfigureAwait(true) is required to ensure that tasks continue on the captured context
|
||||
await provider.Delay(TimeSpan.FromSeconds(delay)).ConfigureAwait(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = simulatedPollyRetry();
|
||||
|
||||
for (int i = 0; i < retries; i++)
|
||||
{
|
||||
// advance time for simulated task delay
|
||||
provider.Advance(TimeSpan.FromSeconds(taskDelay));
|
||||
|
||||
// advance time for retry delay
|
||||
provider.Advance(TimeSpan.FromSeconds(delay));
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsCompleted);
|
||||
Assert.Equal(retries, tries);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Libraries\Microsoft.Extensions.TimeProvider.Testing\Microsoft.Extensions.TimeProvider.Testing.csproj"/>
|
||||
<ProjectReference Include="..\..\..\src\Libraries\Microsoft.Extensions.TimeProvider.Testing\Microsoft.Extensions.TimeProvider.Testing.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче