diff --git a/src/IntegrationTests/Infrastructure/DistributedApplicationExtensions.cs b/src/IntegrationTests/Infrastructure/DistributedApplicationExtensions.cs
index a885404..2765d9b 100644
--- a/src/IntegrationTests/Infrastructure/DistributedApplicationExtensions.cs
+++ b/src/IntegrationTests/Infrastructure/DistributedApplicationExtensions.cs
@@ -7,46 +7,12 @@
using System.Security.Cryptography;
using IntegrationTests.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace IntegrationTests.Infrastructure;
public static partial class DistributedApplicationExtensions
{
- internal const string OutputWriterKey = $"{nameof(DistributedApplicationExtensions)}.OutputWriter";
-
- ///
- /// Adds a background service to watch resource status changes and optionally logs.
- ///
- public static IServiceCollection AddResourceWatching(this IServiceCollection services)
- {
- // Add background service to watch resource status changes and optionally logs
- services.AddSingleton();
- services.AddHostedService(sp => sp.GetRequiredService());
-
- return services;
- }
-
- ///
- /// Configures the builder to write logs to the supplied and store for optional assertion later.
- ///
- public static TBuilder WriteOutputTo(this TBuilder builder, TextWriter outputWriter)
- where TBuilder : IDistributedApplicationTestingBuilder
- {
- builder.Services.AddResourceWatching();
-
- // Add a resource log store to capture logs from resources
- builder.Services.AddSingleton();
-
- // Configure the builder's logger to redirect it output & store for assertion later
- builder.Services.AddKeyedSingleton(OutputWriterKey, outputWriter);
- builder.Services.AddSingleton();
- builder.Services.AddSingleton();
-
- return builder;
- }
-
///
/// Ensures all parameters in the application configuration have values set.
///
@@ -149,33 +115,6 @@ public static HttpClient CreateHttpClient(this DistributedApplication app, strin
return httpClient;
}
- ///
- public static async Task StartAsync(this DistributedApplication app, bool waitForResourcesToStart, CancellationToken cancellationToken = default)
- {
- var resourceWatcher = app.Services.GetRequiredService();
- var resourcesStartingTask = waitForResourcesToStart ? resourceWatcher.WaitForResourcesToStart() : Task.CompletedTask;
-
- await app.StartAsync(cancellationToken);
- await resourcesStartingTask;
- }
-
- public static LoggerLogStore GetAppHostLogs(this DistributedApplication app)
- {
- var logStore = app.Services.GetService()
- ?? throw new InvalidOperationException($"Log store service was not registered. Ensure the '{nameof(WriteOutputTo)}' method is called before attempting to get AppHost logs.");
- return logStore;
- }
-
- ///
- /// Gets the logs for all resources in the application.
- ///
- public static ResourceLogStore GetResourceLogs(this DistributedApplication app)
- {
- var logStore = app.Services.GetService()
- ?? throw new InvalidOperationException($"Log store service was not registered. Ensure the '{nameof(WriteOutputTo)}' method is called before attempting to get resource logs."); ;
- return logStore;
- }
-
///
/// Attempts to apply EF migrations for the specified project by sending a request to the migrations endpoint /ApplyDatabaseMigrations.
///
diff --git a/src/IntegrationTests/Infrastructure/LoggerLogStore.cs b/src/IntegrationTests/Infrastructure/LoggerLogStore.cs
deleted file mode 100644
index 3d850dc..0000000
--- a/src/IntegrationTests/Infrastructure/LoggerLogStore.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System.Collections.Concurrent;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-
-namespace IntegrationTests.Infrastructure;
-
-///
-/// Stores logs from instances created from .
-///
-public class LoggerLogStore(IHostEnvironment hostEnvironment)
-{
- private readonly ConcurrentDictionary> _store = [];
-
- public void AddLog(string category, LogLevel level, string message, Exception? exception)
- {
- _store.GetOrAdd(category, _ => []).Add((DateTimeOffset.Now, category, level, message, exception));
- }
-
- public IReadOnlyDictionary> GetLogs()
- {
- return _store.ToDictionary(entry => entry.Key, entry => (IList<(DateTimeOffset, string, LogLevel, string, Exception?)>)entry.Value);
- }
-
- public void EnsureNoErrors()
- {
- var logs = GetLogs();
-
- var errors = logs.SelectMany(kvp => kvp.Value).Where(log => log.Level == LogLevel.Error || log.Level == LogLevel.Critical).ToList();
- //Where(category => category.Value.Any(log => log.Level == LogLevel.Error || log.Level == LogLevel.Critical)).ToList();
- if (errors.Count > 0)
- {
- var appName = hostEnvironment.ApplicationName;
- throw new InvalidOperationException(
- $"AppHost '{appName}' logged errors: {Environment.NewLine}" +
- string.Join(Environment.NewLine, errors.Select(log => $"[{log.Category}] {log.Message}")));
- }
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/ResourceLogStore.cs b/src/IntegrationTests/Infrastructure/ResourceLogStore.cs
deleted file mode 100644
index 14b3ba8..0000000
--- a/src/IntegrationTests/Infrastructure/ResourceLogStore.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Concurrent;
-
-namespace IntegrationTests.Infrastructure;
-
-public class ResourceLogStore
-{
- private readonly ConcurrentDictionary> _logs = [];
-
- internal void Add(IResource resource, IEnumerable logs)
- {
- _logs.GetOrAdd(resource, _ => []).AddRange(logs);
- }
-
- ///
- /// Gets a snapshot of the logs for all resources.
- ///
- public IReadOnlyDictionary> GetLogs() =>
- _logs.ToDictionary(entry => entry.Key, entry => (IReadOnlyList)entry.Value);
-
- ///
- /// Gets the logs for the specified resource in the application.
- ///
- public IReadOnlyList GetLogs(string resourceName)
- {
- var resource = _logs.Keys.FirstOrDefault(k => string.Equals(k.Name, resourceName, StringComparison.OrdinalIgnoreCase));
- if (resource is not null && _logs.TryGetValue(resource, out var logs))
- {
- return logs;
- }
- return [];
- }
-
- ///
- /// Ensures no errors were logged for the specified resource.
- ///
- public void EnsureNoErrors(string resourceName)
- {
- EnsureNoErrors(r => string.Equals(r.Name, resourceName, StringComparison.OrdinalIgnoreCase));
- }
-
- ///
- /// Ensures no errors were logged for the specified resources.
- ///
- public void EnsureNoErrors(Func? resourcePredicate = null, bool throwIfNoResourcesMatch = false)
- {
- var logStore = GetLogs();
-
- var resourcesMatched = 0;
- foreach (var (resource, logs) in logStore)
- {
- if (resourcePredicate is null || resourcePredicate(resource))
- {
- EnsureNoErrors(resource, logs);
- resourcesMatched++;
- }
- }
-
- if (throwIfNoResourcesMatch && resourcesMatched == 0 && resourcePredicate is not null)
- {
- throw new ArgumentException("No resources matched the predicate.", nameof(resourcePredicate));
- }
-
- static void EnsureNoErrors(IResource resource, IEnumerable logs)
- {
- var errors = logs.Where(l => l.IsErrorMessage).ToList();
- if (errors.Count > 0)
- {
- throw new InvalidOperationException($"Resource '{resource.Name}' logged errors: {Environment.NewLine}{string.Join(Environment.NewLine, errors.Select(e => e.Content))}");
- }
- }
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/ResourceWatcher.cs b/src/IntegrationTests/Infrastructure/ResourceWatcher.cs
deleted file mode 100644
index 10472a8..0000000
--- a/src/IntegrationTests/Infrastructure/ResourceWatcher.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-
-namespace IntegrationTests.Infrastructure;
-
-///
-/// A background service that watches for resource start/stop notifications and logs resource state changes.
-///
-internal sealed class ResourceWatcher(
- DistributedApplicationModel appModel,
- ResourceNotificationService resourceNotification,
- ResourceLoggerService resourceLoggerService,
- IServiceProvider serviceProvider,
- ILogger logger)
- : BackgroundService
-{
- private readonly HashSet _waitingToStartResources = new(StringComparer.OrdinalIgnoreCase);
- private readonly HashSet _startedResources = new(StringComparer.OrdinalIgnoreCase);
- private readonly HashSet _waitingToStopResources = new(StringComparer.OrdinalIgnoreCase);
- private readonly HashSet _stoppedResources = new(StringComparer.OrdinalIgnoreCase);
- private readonly Dictionary _resourceState = [];
- private readonly TaskCompletionSource _resourcesStartedTcs = new();
- private readonly TaskCompletionSource _resourcesStoppedTcs = new();
-
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
- logger.LogInformation("Resource watcher started");
-
- var statusWatchableResources = GetStatusWatchableResources().ToList();
- statusWatchableResources.ForEach(r =>
- {
- _waitingToStartResources.Add(r.Name);
- _waitingToStopResources.Add(r.Name);
- });
- logger.LogInformation("Watching {resourceCount} resources for start/stop changes", statusWatchableResources.Count);
-
- // We need to pass the stopping token in here because the ResourceNotificationService doesn't stop on host shutdown in preview.5
- await WatchNotifications(stoppingToken);
-
- logger.LogInformation("Resource watcher stopped");
- }
-
- public override void Dispose()
- {
- _resourcesStartedTcs.TrySetException(new DistributedApplicationException("Resource watcher was disposed while waiting for resources to start, likely due to a timeout"));
- _resourcesStoppedTcs.TrySetException(new DistributedApplicationException("Resource watcher was disposed while waiting for resources to stop, likely due to a timeout"));
- }
-
- public Task WaitForResourcesToStart() => _resourcesStartedTcs.Task;
-
- public Task WaitForResourcesToStop() => _resourcesStoppedTcs.Task;
-
- private async Task WatchNotifications(CancellationToken cancellationToken)
- {
- var logStore = serviceProvider.GetService();
- var outputWriter = serviceProvider.GetKeyedService(DistributedApplicationExtensions.OutputWriterKey);
- var watchingLogs = logStore is not null || outputWriter is not null;
- var loggingResourceIds = new HashSet();
- var logWatchTasks = new List();
-
- logger.LogInformation("Waiting on {resourcesToStartCount} resources to start", _waitingToStartResources.Count);
-
- await foreach (var resourceEvent in resourceNotification.WatchAsync().WithCancellation(cancellationToken))
- {
- var resourceName = resourceEvent.Resource.Name;
- var resourceId = resourceEvent.ResourceId;
-
- if (watchingLogs && loggingResourceIds.Add(resourceId))
- {
- // Start watching the logs for this resource ID
- logWatchTasks.Add(WatchResourceLogs(logStore, outputWriter, resourceEvent.Resource, resourceId, cancellationToken));
- }
-
- _resourceState.TryGetValue(resourceName, out var prevState);
- _resourceState[resourceName] = (resourceEvent.Snapshot.State, resourceEvent.Snapshot.ExitCode);
-
- if (resourceEvent.Snapshot.ExitCode is null && resourceEvent.Snapshot.State is { } newState && !string.IsNullOrEmpty(newState.Text))
- {
- if (!string.Equals(prevState.Snapshot?.Text, newState.Text, StringComparison.OrdinalIgnoreCase))
- {
- // Log resource state change
- logger.LogInformation("Resource '{resourceName}' of type '{resourceType}' changed state: {oldState} -> {newState}", resourceId, resourceEvent.Resource.GetType().Name, prevState.Snapshot?.Text ?? "[null]", newState.Text);
-
- if (newState.Text.Contains("running", StringComparison.OrdinalIgnoreCase))
- {
- // Resource started
- HandleResourceStarted(resourceEvent.Resource);
- }
- else if (newState.Text.Contains("failedtostart", StringComparison.OrdinalIgnoreCase))
- {
- // Resource failed to start
- HandleResourceStartError(resourceName, $"Resource '{resourceName}' failed to start: {newState.Text}");
- }
- else if (newState.Text.Contains("exited", StringComparison.OrdinalIgnoreCase))
- {
- if (_waitingToStartResources.Contains(resourceEvent.Resource.Name))
- {
- // Resource went straight to exited state
- HandleResourceStartError(resourceName, $"Resource '{resourceName}' exited without first running: {newState.Text}");
- }
-
- // Resource stopped
- HandleResourceStopped(resourceEvent.Resource);
- }
- else if (newState.Text.Contains("starting", StringComparison.OrdinalIgnoreCase)
- || newState.Text.Contains("hidden", StringComparison.OrdinalIgnoreCase))
- {
- // Resource is still starting
- }
- else if (!string.IsNullOrEmpty(newState.Text))
- {
- logger.LogWarning("Unknown resource state encountered: {state}", newState.Text);
- }
- }
- }
- else if (resourceEvent.Snapshot.ExitCode is { } exitCode)
- {
- if (exitCode != 0)
- {
- if (_waitingToStartResources.Remove(resourceName))
- {
- // Error starting resource
- HandleResourceStartError(resourceName, $"Resource '{resourceName}' exited with exit code {exitCode}");
- }
- HandleResourceStopError(resourceName, $"Resource '{resourceName}' exited with exit code {exitCode}");
- }
- else
- {
- // Resource exited cleanly
- HandleResourceStarted(resourceEvent.Resource, " (exited with code 0)");
- HandleResourceStopped(resourceEvent.Resource, " (exited with code 0)");
- }
- }
-
- if (_waitingToStartResources.Count == 0)
- {
- logger.LogInformation("All resources started");
- _resourcesStartedTcs.TrySetResult();
- }
-
- if (_waitingToStopResources.Count == 0)
- {
- logger.LogInformation("All resources stopped");
- _resourcesStoppedTcs.TrySetResult();
- }
- }
-
- void HandleResourceStartError(string resourceName, string message)
- {
- if (_waitingToStartResources.Remove(resourceName))
- {
- _resourcesStartedTcs.TrySetException(new DistributedApplicationException(message));
- }
- _waitingToStopResources.Remove(resourceName);
- _stoppedResources.Add(resourceName);
- }
-
- void HandleResourceStopError(string resourceName, string message)
- {
- _waitingToStartResources.Remove(resourceName);
- if (_waitingToStopResources.Remove(resourceName))
- {
- _resourcesStoppedTcs.TrySetException(new DistributedApplicationException(message));
- }
- _stoppedResources.Add(resourceName);
- }
-
- void HandleResourceStarted(IResource resource, string? suffix = null)
- {
- if (_waitingToStartResources.Remove(resource.Name) && _startedResources.Add(resource.Name))
- {
-#pragma warning disable CA2254 // Template should be a static expression: suffix is not log data
- logger.LogInformation($"Resource '{{resourceName}}' started{suffix}", resource.Name);
-#pragma warning restore CA2254
- }
-
- if (_waitingToStartResources.Count > 0)
- {
- var resourceNames = string.Join(", ", _waitingToStartResources.Select(r => r));
- logger.LogInformation("Still waiting on {resourcesToStartCount} resources to start: {resourcesToStart}", _waitingToStartResources.Count, resourceNames);
- }
- }
-
- void HandleResourceStopped(IResource resource, string? suffix = null)
- {
- if (_waitingToStopResources.Remove(resource.Name) && _stoppedResources.Add(resource.Name))
- {
-#pragma warning disable CA2254 // Template should be a static expression: suffix is not log data
- logger.LogInformation($"Resource '{{resourceName}}' stopped{suffix}", resource.Name);
-#pragma warning restore CA2254
- }
-
- if (_waitingToStopResources.Count > 0)
- {
- var resourceNames = string.Join(", ", _waitingToStopResources.Select(r => r));
- logger.LogInformation("Still waiting on {resourcesToStartCount} resources to stop: {resourcesToStart}", _waitingToStopResources.Count, resourceNames);
- }
- }
-
- await Task.WhenAll(logWatchTasks);
- }
-
- private async Task WatchResourceLogs(ResourceLogStore? logStore, TextWriter? outputWriter, IResource resource, string resourceId, CancellationToken cancellationToken)
- {
- if (logStore is not null || outputWriter is not null)
- {
- await foreach (var logEvent in resourceLoggerService.WatchAsync(resourceId).WithCancellation(cancellationToken))
- {
- logStore?.Add(resource, logEvent);
-
- foreach (var line in logEvent)
- {
- var kind = line.IsErrorMessage ? "error" : "log";
- outputWriter?.WriteLine("{0} Resource '{1}' {2}: {3}", DateTime.Now.ToString("O"), resource.Name, kind, line.Content);
- }
- }
- }
- }
-
- private IEnumerable GetStatusWatchableResources()
- {
- return appModel.Resources.Where(r => r is ContainerResource || r is ExecutableResource || r is ProjectResource);
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/StoredLogsLogger.cs b/src/IntegrationTests/Infrastructure/StoredLogsLogger.cs
deleted file mode 100644
index a513c8b..0000000
--- a/src/IntegrationTests/Infrastructure/StoredLogsLogger.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Microsoft.Extensions.Logging;
-
-namespace IntegrationTests.Infrastructure;
-
-///
-/// A logger that stores logs in a .
-///
-///
-///
-///
-internal class StoredLogsLogger(LoggerLogStore logStore, LoggerExternalScopeProvider scopeProvider, string categoryName) : ILogger
-{
- public string CategoryName { get; } = categoryName;
-
- public IDisposable? BeginScope(TState state) where TState : notnull => scopeProvider.Push(state);
-
- public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
-
- public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter)
- {
- logStore.AddLog(CategoryName, logLevel, formatter(state, exception), exception);
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/StoredLogsLoggerProvider.cs b/src/IntegrationTests/Infrastructure/StoredLogsLoggerProvider.cs
deleted file mode 100644
index 0b4c796..0000000
--- a/src/IntegrationTests/Infrastructure/StoredLogsLoggerProvider.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Microsoft.Extensions.Logging;
-
-namespace IntegrationTests.Infrastructure;
-
-///
-/// A logger provider that stores logs in an .
-///
-internal class StoredLogsLoggerProvider(LoggerLogStore logStore) : ILoggerProvider
-{
- private readonly LoggerExternalScopeProvider _scopeProvider = new();
-
- public ILogger CreateLogger(string categoryName)
- {
- return new StoredLogsLogger(logStore, _scopeProvider, categoryName);
- }
-
- public void Dispose()
- {
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/XUnitExtensions.cs b/src/IntegrationTests/Infrastructure/XUnitExtensions.cs
deleted file mode 100644
index 29d9f0c..0000000
--- a/src/IntegrationTests/Infrastructure/XUnitExtensions.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-using Xunit.Abstractions;
-
-namespace IntegrationTests.Infrastructure;
-
-internal static partial class DistributedApplicationTestFactory
-{
- /////
- ///// Creates an for the specified app host assembly and outputs logs to the provided .
- /////
- //public static async Task CreateAsync(string appHostAssemblyPath, ITestOutputHelper testOutputHelper)
- //{
- // var builder = await CreateAsync(appHostAssemblyPath, new XUnitTextWriter(testOutputHelper));
- // builder.Services.AddSingleton();
- // builder.Services.AddSingleton(testOutputHelper);
- // return builder;
- //}
-
- ///
- /// Writes messages and resource logs to the provided .
- ///
- /// The builder.
- /// The output.
- /// The builder.
- public static IDistributedApplicationTestingBuilder WriteOutputTo(this IDistributedApplicationTestingBuilder builder, ITestOutputHelper testOutputHelper)
- {
- // Enable the core ILogger and resource output capturing
- builder.WriteOutputTo(new XUnitTextWriter(testOutputHelper));
-
- // Enable ILogger going to xUnit output
- builder.Services.AddSingleton(testOutputHelper);
- builder.Services.AddSingleton();
-
- return builder;
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/XUnitLogger.cs b/src/IntegrationTests/Infrastructure/XUnitLogger.cs
deleted file mode 100644
index ab5b1ea..0000000
--- a/src/IntegrationTests/Infrastructure/XUnitLogger.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Text;
-using Microsoft.Extensions.Logging;
-using Xunit.Abstractions;
-
-namespace IntegrationTests.Infrastructure;
-
-///
-/// An that writes log messages to an .
-///
-internal class XUnitLogger(ITestOutputHelper testOutputHelper, LoggerExternalScopeProvider scopeProvider, string categoryName) : ILogger
-{
- public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
-
- public IDisposable? BeginScope(TState state) where TState : notnull => scopeProvider.Push(state);
-
- public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter)
- {
- var sb = new StringBuilder();
-
- sb.Append(DateTime.Now.ToString("O")).Append(' ')
- .Append(GetLogLevelString(logLevel))
- .Append(" [").Append(categoryName).Append("] ")
- .Append(formatter(state, exception));
-
- if (exception is not null)
- {
- sb.AppendLine().Append(exception);
- }
-
- // Append scopes
- scopeProvider.ForEachScope((scope, state) =>
- {
- state.AppendLine();
- state.Append(" => ");
- state.Append(scope);
- }, sb);
-
- testOutputHelper.WriteLine(sb.ToString());
- }
-
- private static string GetLogLevelString(LogLevel logLevel)
- {
- return logLevel switch
- {
- LogLevel.Trace => "trce",
- LogLevel.Debug => "dbug",
- LogLevel.Information => "info",
- LogLevel.Warning => "warn",
- LogLevel.Error => "fail",
- LogLevel.Critical => "crit",
- _ => throw new ArgumentOutOfRangeException(nameof(logLevel))
- };
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/XUnitLoggerProvider.cs b/src/IntegrationTests/Infrastructure/XUnitLoggerProvider.cs
deleted file mode 100644
index 235f351..0000000
--- a/src/IntegrationTests/Infrastructure/XUnitLoggerProvider.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Microsoft.Extensions.Logging;
-using Xunit.Abstractions;
-
-namespace IntegrationTests.Infrastructure;
-
-///
-/// An that creates instances that output to the supplied .
-///
-internal class XUnitLoggerProvider(ITestOutputHelper testOutputHelper) : ILoggerProvider
-{
- private readonly LoggerExternalScopeProvider _scopeProvider = new();
-
- public ILogger CreateLogger(string categoryName)
- {
- return new XUnitLogger(testOutputHelper, _scopeProvider, categoryName);
- }
-
- public void Dispose()
- {
- }
-}
diff --git a/src/IntegrationTests/Infrastructure/XUnitTextWriter.cs b/src/IntegrationTests/Infrastructure/XUnitTextWriter.cs
deleted file mode 100644
index 31a3046..0000000
--- a/src/IntegrationTests/Infrastructure/XUnitTextWriter.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Text;
-using Xunit.Abstractions;
-
-namespace IntegrationTests.Infrastructure;
-
-///
-/// A that writes to an .
-///
-internal class XUnitTextWriter(ITestOutputHelper output) : TextWriter
-{
- private readonly StringBuilder _sb = new();
-
- public override Encoding Encoding => Encoding.Unicode;
-
- public override void Write(char value)
- {
- if (value == '\r' || value == '\n')
- {
- if (_sb.Length > 0)
- {
- output.WriteLine(_sb.ToString());
- _sb.Clear();
- }
- }
- else
- {
- _sb.Append(value);
- }
- }
-}
diff --git a/src/IntegrationTests/IntegrationTests.csproj b/src/IntegrationTests/IntegrationTests.csproj
index e8722bc..c211edd 100644
--- a/src/IntegrationTests/IntegrationTests.csproj
+++ b/src/IntegrationTests/IntegrationTests.csproj
@@ -17,6 +17,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/src/IntegrationTests/WebAppTests.cs b/src/IntegrationTests/WebAppTests.cs
index f4089a7..a676f7a 100644
--- a/src/IntegrationTests/WebAppTests.cs
+++ b/src/IntegrationTests/WebAppTests.cs
@@ -1,6 +1,7 @@
using System.Net;
using IntegrationTests.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Xunit.Abstractions;
namespace IntegrationTests;
@@ -11,7 +12,9 @@ public class WebAppTests(ITestOutputHelper outputHelper)
public async Task GetWebAppUrlsReturnsOkStatusCode()
{
var appHostBuilder = await DistributedApplicationTestingBuilder.CreateAsync();
- appHostBuilder.WriteOutputTo(outputHelper);
+
+ appHostBuilder.Services.AddLogging(logging => logging.AddXUnit(outputHelper));
+
appHostBuilder.WithRandomParameterValues();
appHostBuilder.WithRandomVolumeNames();
@@ -30,7 +33,11 @@ public async Task GetWebAppUrlsReturnsOkStatusCode()
});
await using var app = await appHostBuilder.BuildAsync();
- await app.StartAsync(waitForResourcesToStart: true);
+
+ var notificationService = app.Services.GetRequiredService();
+ await notificationService.WaitForResourceAsync("webapp").WaitAsync(TimeSpan.FromSeconds(30));
+
+ await app.StartAsync();
var httpClient = app.CreateHttpClient("webapp");
diff --git a/src/eShop.ServiceDefaults/eShop.ServiceDefaults.csproj b/src/eShop.ServiceDefaults/eShop.ServiceDefaults.csproj
index cfd3f49..bb4d68f 100644
--- a/src/eShop.ServiceDefaults/eShop.ServiceDefaults.csproj
+++ b/src/eShop.ServiceDefaults/eShop.ServiceDefaults.csproj
@@ -17,7 +17,7 @@
-
+