-
Notifications
You must be signed in to change notification settings - Fork 288
Description
Describe the bug
When MTP extension implements both ITestHostApplicationLifetime/IAsyncCleanableExtension.
IAsyncCleanableExtension::CleanupAsync method seems to be called twice.
It's confirmed it can reproduced on version 2.0.0-preview.25372.6.
And it also reproduced with version 1.7.2 (Using ITestApplicationLifecycleCallbacks)
Steps To Reproduce
1. Create console application
2. Reference Microsoft.Testing.Platform 2.0.0-preview.25372.6 package
3. Paste following test code and run console app
using Microsoft.Testing.Platform.Builder;
using Microsoft.Testing.Platform.Capabilities.TestFramework;
using Microsoft.Testing.Platform.Extensions;
using Microsoft.Testing.Platform.Extensions.Messages;
using Microsoft.Testing.Platform.Extensions.TestFramework;
using Microsoft.Testing.Platform.Extensions.TestHost;
using Microsoft.Testing.Platform.Requests;
namespace TestConsoleApp;
#pragma warning disable TPEXP
internal class Program
{
static async Task<int> Main(string[] args)
{
var builder = await TestApplication.CreateBuilderAsync(args);
var testFramework = new DummyTestAdapter();
builder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, _) => testFramework);
var myExtension = new MyExtension(testFramework);
builder.TestHost.AddTestHostApplicationLifetime(_ => myExtension);
// builder.TestHost.AddDataConsumer(_ => myExtension);
var app = await builder.BuildAsync();
return await app.RunAsync();
}
}
internal class MyExtension(IExtension extension) : ITestHostApplicationLifetime, IAsyncCleanableExtension
{
public Task<bool> IsEnabledAsync() => extension.IsEnabledAsync();
public string Uid => extension.Uid;
public string Version => extension.Version;
public string DisplayName => extension.DisplayName;
public string Description => extension.Description;
public Task BeforeRunAsync(CancellationToken cancellationToken)
{
Console.WriteLine("BeforeRunAsync");
return Task.CompletedTask;
}
public Task AfterRunAsync(int exitCode, CancellationToken cancellation)
{
Console.WriteLine("AfterRunAsync");
return Task.CompletedTask;
}
public Task CleanupAsync()
{
Console.WriteLine("CleanupAsync");
return Task.CompletedTask;
}
}
internal class DummyTestAdapter : ITestFramework, IDataProducer
{
public Task<bool> IsEnabledAsync() => Task.FromResult(true);
public string Uid => nameof(DummyTestAdapter);
public string Version => string.Empty;
public string DisplayName => string.Empty;
public string Description => string.Empty;
public Type[] DataTypesProduced => [typeof(TestNodeUpdateMessage)];
public Task<CloseTestSessionResult> CloseTestSessionAsync(CloseTestSessionContext context) => Task.FromResult(new CloseTestSessionResult { IsSuccess = true });
public Task<CreateTestSessionResult> CreateTestSessionAsync(CreateTestSessionContext context) => Task.FromResult(new CreateTestSessionResult { IsSuccess = true });
public async Task ExecuteRequestAsync(ExecuteRequestContext context)
{
switch (context.Request)
{
case DiscoverTestExecutionRequest discoverRequest:
case RunTestExecutionRequest runRequest:
await Task.Yield();
//await HandleRequest(context);
break;
default:
break;
}
context.Complete();
}
}
Expected behavior
CleanupAsync is expected to be called exactly once.
Because CleanupAsync method has no special note that
it may be called multiple times like Dispose/DisposeAsync.
Actual behavior
CleanupAsync log outputted twice..
Additional context
It seems to be disposed at following lines.
- https://github.com/microsoft/testfx/blob/v4.0.0-preview.25372.6/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs#L123
- https://github.com/microsoft/testfx/blob/v4.0.0-preview.25372.6/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs#L256
Additionally,
Following lines seems redundant because it checks same types.
https://github.com/microsoft/testfx/blob/v4.0.0-preview.25372.6/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs#L246-L247