Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[browser] Debug RunWithDifferentAppBundleLocations times out #98981

Closed
105 changes: 94 additions & 11 deletions src/mono/wasm/Wasm.Build.Tests/BrowserRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
using Microsoft.Playwright;
using Wasm.Tests.Internal;
using Xunit.Abstractions;
using System.Diagnostics;
using System.Text.Json;
using System.Linq;

namespace Wasm.Build.Tests;

Expand All @@ -37,8 +40,10 @@ internal class BrowserRunner : IAsyncDisposable
public async Task<string> StartServerAndGetUrlAsync(
ToolCommand cmd,
string args,
Action<string>? onServerMessage = null
) {
Action<string>? onServerMessage = null,
string? projectDir = null
)
{
TaskCompletionSource<string> urlAvailable = new();
Action<string?> outputHandler = msg =>
{
Expand Down Expand Up @@ -76,6 +81,22 @@ public async Task<string> StartServerAndGetUrlAsync(
var runTask = cmd.ExecuteAsync(args);

await Task.WhenAny(runTask, urlAvailable.Task, Task.Delay(TimeSpan.FromSeconds(30)));

string? launchContent = null;
if (projectDir != null)
{
string launchFile = Path.Combine(projectDir, "Properties", "launchSettings.json");
if (File.Exists(launchFile))
{
launchContent = File.ReadAllText(launchFile);
_testOutput.WriteLine($"launchSettings.json: {launchContent}");
}
else
{
_testOutput.WriteLine("launchSettings.json: Doesn't exist");
}
}

if (runTask.IsCompleted)
{
var res = await runTask;
Expand All @@ -84,7 +105,49 @@ public async Task<string> StartServerAndGetUrlAsync(
throw new Exception($"Process ended before the url was found");
}
if (!urlAvailable.Task.IsCompleted)
throw new Exception("Timed out waiting for the web server url");
{
if (launchContent != null)
{
var jsonOptions = new JsonSerializerOptions()
{
AllowTrailingCommas = true
};
var launchSettings = JsonSerializer.Deserialize<RootObject>(launchContent, jsonOptions);
if (launchSettings != null && launchSettings.profiles != null && launchSettings.profiles.Count > 0)
{
var firstServerUrl = launchSettings.profiles.First().Value.applicationUrl?.Split(";", StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
if (firstServerUrl != null)
{
_testOutput.WriteLine($"launchSettings.json: The process '{cmd.CurrentProcess?.Id}' didn't provided URLs, but found server URL {firstServerUrl} in launch settings");
urlAvailable.TrySetResult(firstServerUrl);
}
}
else
{
_testOutput.WriteLine($"launchSettings.json: Did not find any profiles or applicationUrl in launch settings");
}
}

if (!urlAvailable.Task.IsCompleted)
{
foreach (var p in Process.GetProcesses())
{
string processMsg = $"Process: {p.Id} - {p.ProcessName}";
try
{
processMsg += $" - {p.MainModule?.FileName}";
}
catch (Exception e)
{
processMsg += $" - Failed to get MainModule - {e.Message}";
}

_testOutput.WriteLine(processMsg);
}

throw new Exception("Timed out waiting for the web server url");
}
}

RunTask = runTask;
return urlAvailable.Task.Result;
Expand All @@ -93,13 +156,15 @@ public async Task<string> StartServerAndGetUrlAsync(
public async Task<IBrowser> SpawnBrowserAsync(
string browserUrl,
bool headless = true
) {
)
{
var url = new Uri(browserUrl);
Playwright = await Microsoft.Playwright.Playwright.CreateAsync();
// codespaces: ignore certificate error -> Microsoft.Playwright.PlaywrightException : net::ERR_CERT_AUTHORITY_INVALID
string[] chromeArgs = new[] { $"--explicitly-allowed-ports={url.Port}", "--ignore-certificate-errors" };
_testOutput.WriteLine($"Launching chrome ('{s_chromePath.Value}') via playwright with args = {string.Join(',', chromeArgs)}");
return Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions{
return Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
ExecutablePath = s_chromePath.Value,
Headless = headless,
Args = chromeArgs
Expand All @@ -115,9 +180,10 @@ public async Task<IPage> RunAsync(
Action<IPage>? onPageLoaded = null,
Action<string>? onServerMessage = null,
Action<string>? onError = null,
Func<string, string>? modifyBrowserUrl = null)
Func<string, string>? modifyBrowserUrl = null,
string? projectDir = null)
{
var urlString = await StartServerAndGetUrlAsync(cmd, args, onServerMessage);
var urlString = await StartServerAndGetUrlAsync(cmd, args, onServerMessage, projectDir);
var browser = await SpawnBrowserAsync(urlString, headless);
var context = await browser.NewContextAsync();
return await RunAsync(context, urlString, headless, onPageLoaded, onConsoleMessage, onError, modifyBrowserUrl);
Expand All @@ -132,9 +198,10 @@ public async Task<IPage> RunAsync(
Action<string>? onError = null,
Func<string, string>? modifyBrowserUrl = null,
bool resetExitedState = false
) {
)
{
if (resetExitedState)
_exited = new ();
_exited = new();

if (modifyBrowserUrl != null)
browserUrl = modifyBrowserUrl(browserUrl);
Expand Down Expand Up @@ -166,7 +233,7 @@ public async Task WaitForExitMessageAsync(TimeSpan timeout)
await Task.WhenAny(RunTask!, _exited.Task, Task.Delay(timeout));
if (_exited.Task.IsCompleted)
{
_testOutput.WriteLine ($"Exited with {await _exited.Task}");
_testOutput.WriteLine($"Exited with {await _exited.Task}");
return;
}

Expand All @@ -181,7 +248,7 @@ public async Task WaitForProcessExitAsync(TimeSpan timeout)
await Task.WhenAny(RunTask!, _exited.Task, Task.Delay(timeout));
if (RunTask.IsCanceled)
{
_testOutput.WriteLine ($"Exited with {(await RunTask).ExitCode}");
_testOutput.WriteLine($"Exited with {(await RunTask).ExitCode}");
return;
}

Expand All @@ -195,3 +262,19 @@ public async ValueTask DisposeAsync()
Playwright?.Dispose();
}
}


public class RootObject
{
public Dictionary<string, ProfileObject>? profiles { get; set; }
}

public class ProfileObject
{
public string? commandName { get; set; }
public bool launchBrowser { get; set; }
public Dictionary<string, string>? environmentVariables { get; set; }
public string? applicationUrl { get; set; }
public string? inspectUri { get; set; }
}

4 changes: 4 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,14 @@ private async Task<CommandResult> ExecuteAsyncInternal(string executable, string
};

var completionTask = CurrentProcess.StartAndWaitForExitAsync();
_testOutput.WriteLine($"[{_label}] CurrentProcess {CurrentProcess.Id}");

CurrentProcess.BeginOutputReadLine();
CurrentProcess.BeginErrorReadLine();
await completionTask;

_testOutput.WriteLine($"[{_label}] CurrentProcess exited {CurrentProcess.Id} {CurrentProcess.ExitCode}");

RemoveNullTerminator(output);

return new CommandResult(
Expand Down
21 changes: 20 additions & 1 deletion src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Playwright;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
Expand Down Expand Up @@ -289,7 +290,25 @@ private async Task BrowserRunTwiceWithAndThenWithoutBuildAsync(string config, st
.WithWorkingDirectory(workingDir);

await using var runner = new BrowserRunner(_testOutput);
var page = await runner.RunAsync(runCommand, $"run --no-silent -c {config} --project \"{projectFile}\" --forward-console");
IPage? page = null;
int iteration = 0;
while (page == null && iteration < 3)
{
try
{
page = await runner.RunAsync(runCommand, $"run --no-silent -c {config} --project \"{projectFile}\" --forward-console", projectDir: _projectDir);
}
catch (Exception e) when(e.Message == "Timed out waiting for the web server url")
{
_testOutput.WriteLine($"Exception (iteration: {iteration}): {e}");
iteration++;
continue;
}
}

if (page == null)
throw new Exception("Timed out waiting for the web server url (after retry)");

await runner.WaitForExitMessageAsync(TimeSpan.FromMinutes(2));
Assert.Contains("Hello, Browser!", string.Join(Environment.NewLine, runner.OutputLines));
}
Expand Down
Loading