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

[wasm][debugger] Fix some racy tests #73524

Merged
merged 15 commits into from
Aug 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/mono/wasm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ submit-tests-helix:
run-debugger-tests:
rm -f $(TOP)/artifacts/bin/DebuggerTestSuite/x64/Debug/*log; \
if [ ! -z "$(TEST_FILTER)" ]; then \
$(DOTNET) test $(TOP)/src/mono/wasm/debugger/DebuggerTestSuite $(MSBUILD_ARGS) "-l:trx;LogFileName=DebuggerTestsResults.xml" --results-directory $(TOP)/artifacts/log/$(CONFIG) --filter "Category!=failing&FullyQualifiedName~$(TEST_FILTER)" $(TEST_ARGS); \
$(DOTNET) test $(TOP)/src/mono/wasm/debugger/DebuggerTestSuite $(MSBUILD_ARGS) "-l:trx;LogFileName=DebuggerTestsResults.xml" --results-directory $(TOP)/artifacts/log/$(CONFIG) --filter "Category!=failing&FullyQualifiedName$(TEST_FILTER)" $(TEST_ARGS); \
else \
$(DOTNET) test $(TOP)/src/mono/wasm/debugger/DebuggerTestSuite $(MSBUILD_ARGS) "-l:trx;LogFileName=DebuggerTestsResults.xml" --results-directory $(TOP)/artifacts/log/$(CONFIG) --filter "Category!=failing" $(TEST_ARGS); \
fi
Expand Down
6 changes: 5 additions & 1 deletion src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,11 @@ private async Task<bool> OnJSEventRaised(SessionId sessionId, JObject eventArgs,
return false;
}

logger.LogDebug($"OnJsEventRaised: args: {eventArgs}");
string eventStr = eventArgs.ToString();
string newStr = eventStr.Substring(0, Math.Min(1024, eventStr.Length));
if (newStr.Length != eventStr.Length)
newStr += " ... truncated }";
logger.LogDebug($"OnJsEventRaised: args: {newStr}");

switch (eventName)
{
Expand Down
25 changes: 12 additions & 13 deletions src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ public async Task CreateGoodBreakpointAndHitGoToNonWasmPageComeBackAndHitAgain()
expression = "window.setTimeout(function() { reload_wasm_page(); }, 1);"
});
await cli.SendCommand("Runtime.evaluate", run_method, token);
await insp.WaitFor(Inspector.READY);
await insp.WaitFor(Inspector.APP_READY);
await EvaluateAndCheck(
"window.setTimeout(function() { invoke_add(); }, 1);",
"dotnet://debugger-test.dll/debugger-test.cs", 10, 8,
Expand Down Expand Up @@ -592,10 +592,10 @@ await SendCommandAndCheck(null, "Debugger.resume",
[InlineData(true, "RunNonUserCode", "DebuggerAttribute", 1, 867, 8, "DebuggerAttribute.RunNonUserCode")]
[InlineData(false, "RunStepThroughWithNonUserCode", "DebuggerAttribute", 1, 933, 8, "DebuggerAttribute.RunStepThroughWithNonUserCode")]
[InlineData(true, "RunStepThroughWithNonUserCode", "DebuggerAttribute", 1, 933, 8, "DebuggerAttribute.RunStepThroughWithNonUserCode")]
[InlineData(false, "EvaluateStepThroughAttr", "DefaultInterfaceMethod", 2, 1108, 4, "DefaultInterfaceMethod.EvaluateStepThroughAttr")]
[InlineData(true, "EvaluateStepThroughAttr", "DefaultInterfaceMethod", 2, 1108, 4, "DefaultInterfaceMethod.EvaluateStepThroughAttr")]
[InlineData(false, "EvaluateNonUserCodeAttr", "DefaultInterfaceMethod", 2, 1065, 4, "IExtendIDefaultInterface.NonUserCodeDefaultMethod")]
[InlineData(true, "EvaluateNonUserCodeAttr", "DefaultInterfaceMethod", 2, 1114, 4, "DefaultInterfaceMethod.EvaluateNonUserCodeAttr")]
[InlineData(false, "EvaluateStepThroughAttr", "DefaultInterfaceMethod", 2, 1110, 4, "DefaultInterfaceMethod.EvaluateStepThroughAttr")]
[InlineData(true, "EvaluateStepThroughAttr", "DefaultInterfaceMethod", 2, 1110, 4, "DefaultInterfaceMethod.EvaluateStepThroughAttr")]
[InlineData(false, "EvaluateNonUserCodeAttr", "DefaultInterfaceMethod", 2, 1067, 4, "IExtendIDefaultInterface.NonUserCodeDefaultMethod")]
[InlineData(true, "EvaluateNonUserCodeAttr", "DefaultInterfaceMethod", 2, 1116, 4, "DefaultInterfaceMethod.EvaluateNonUserCodeAttr")]
public async Task StepThroughOrNonUserCodeAttributeStepInNoBp2(bool justMyCodeEnabled, string evalFunName, string evalClassName, int bpLine, int line, int col, string funcName="")
{
var bp_init = await SetBreakpointInMethod("debugger-test.dll", evalClassName, evalFunName, bpLine);
Expand Down Expand Up @@ -785,14 +785,14 @@ public async Task CreateGoodBreakpointAndHitGoToWasmPageWithoutAssetsComeBackAnd
expression = "window.setTimeout(function() { load_wasm_page_without_assets(); }, 1);"
});
await cli.SendCommand("Runtime.evaluate", run_method, token);
await insp.WaitFor(Inspector.READY);
await insp.WaitFor(Inspector.APP_READY);

run_method = JObject.FromObject(new
{
expression = "window.setTimeout(function() { reload_wasm_page(); }, 1);"
});
await cli.SendCommand("Runtime.evaluate", run_method, token);
await insp.WaitFor(Inspector.READY);
await insp.WaitFor(Inspector.APP_READY);

await EvaluateAndCheck(
"window.setTimeout(function() { invoke_add(); }, 1);",
Expand Down Expand Up @@ -823,11 +823,11 @@ await EvaluateAndCheck(
}

[Theory]
[InlineData("IDefaultInterface", "DefaultMethod", "Evaluate", "DefaultInterfaceMethod.Evaluate", 1087, 1003, 1001, 1005)]
[InlineData("IExtendIDefaultInterface", "IDefaultInterface.DefaultMethodToOverride", "Evaluate", "DefaultInterfaceMethod.Evaluate", 1088, 1047, 1045, 1049)]
[InlineData("IDefaultInterface", "DefaultMethodAsync", "EvaluateAsync", "System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<IDefaultInterface.<DefaultMethodAsync>d__3>", 37, 1016, 1014, 1018)]
[InlineData("IDefaultInterface", "DefaultMethodStatic", "EvaluateStatic", "DefaultInterfaceMethod.EvaluateStatic", 1124, 1022, 1020, 1024)]
[InlineData("IDefaultInterface", "DefaultMethodAsyncStatic", "EvaluateAsyncStatic", "System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<IDefaultInterface.<DefaultMethodAsyncStatic>d__5>", 37, 1031, 1029, 1033)]
[InlineData("IDefaultInterface", "DefaultMethod", "Evaluate", "DefaultInterfaceMethod.Evaluate", 1089, 1005, 1003, 1007)]
[InlineData("IExtendIDefaultInterface", "IDefaultInterface.DefaultMethodToOverride", "Evaluate", "DefaultInterfaceMethod.Evaluate", 1090, 1049, 1047, 1051)]
[InlineData("IDefaultInterface", "DefaultMethodAsync", "EvaluateAsync", "System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<IDefaultInterface.<DefaultMethodAsync>d__3>", 37, 1018, 1016, 1020)]
[InlineData("IDefaultInterface", "DefaultMethodStatic", "EvaluateStatic", "DefaultInterfaceMethod.EvaluateStatic", 1126, 1024, 1022, 1026)]
[InlineData("IDefaultInterface", "DefaultMethodAsyncStatic", "EvaluateAsyncStatic", "System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<IDefaultInterface.<DefaultMethodAsyncStatic>d__5>", 37, 1033, 1031, 1035)]
public async Task BreakInDefaultInterfaceMethod(
string dimClassName, string dimName, string entryMethod, string prevFrameInDim, int evaluateAsPrevFrameLine, int dimAsPrevFrameLine, int functionLocationLine, int functionEndLine)
{
Expand Down Expand Up @@ -860,7 +860,6 @@ public async Task BreakInDefaultInterfaceMethod(
Assert.Equal(pauseInFunCalledFromDim["callFrames"][1]["functionName"].Value<string>(), dimClassName + "." + prevFrameFromDim);
CheckLocationLine(pauseInFunCalledFromDim["callFrames"][1]["location"], dimAsPrevFrameLine);


async Task CheckDefaultMethod(JObject pause_location, string methodName)
{
Assert.Equal("other", pause_location["reason"]?.Value<string>());
Expand Down
18 changes: 15 additions & 3 deletions src/mono/wasm/debugger/DebuggerTestSuite/ChromeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using System.Threading;
using System.Collections.Generic;
using Wasm.Tests.Internal;
using System.Linq;

#nullable enable

Expand All @@ -30,6 +31,11 @@ internal class ChromeProvider : WasmHostProvider
string artifactsBinDir = Path.Combine(Path.GetDirectoryName(typeof(ChromeProvider).Assembly.Location)!, "..", "..", "..");
return BrowserLocator.FindChrome(artifactsBinDir, "BROWSER_PATH_FOR_TESTS");
});
private static readonly string[] s_messagesToFilterOut = new[]
{
"Received unexpected number of handles",
"Failed to connect to the bus:",
};

public ChromeProvider(string id, ILogger logger) : base(id, logger)
{
Expand Down Expand Up @@ -104,6 +110,14 @@ public override void Dispose()
_isDisposing = false;
}

protected override bool ShouldMessageBeLogged(string prefix, string? msg)
{
if (msg is null || !prefix.Contains("browser-stderr"))
return true;

return !s_messagesToFilterOut.Any(f => msg.Contains(f));
}

private async Task<string> ExtractConnUrl (string str, ILogger logger)
{
var client = new HttpClient();
Expand All @@ -119,7 +133,7 @@ private async Task<string> ExtractConnUrl (string str, ILogger logger)
await Task.Delay(100);

var res = await client.GetStringAsync(new Uri(new Uri(str), "/json/list"));
logger.LogInformation("res is {0}", res);
logger.LogTrace("res is {0}", res);

if (!string.IsNullOrEmpty(res))
{
Expand Down Expand Up @@ -157,6 +171,4 @@ private static string GetInitParms(int port)
}
return str;
}


}
113 changes: 80 additions & 33 deletions src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,30 +159,32 @@ internal virtual Dictionary<string, string> SubscribeToScripts(Inspector insp)
{
dicScriptsIdToUrl = new Dictionary<string, string>();
dicFileToUrl = new Dictionary<string, string>();
insp.On("Debugger.scriptParsed", async (args, c) =>
{
var script_id = args?["scriptId"]?.Value<string>();
var url = args["url"]?.Value<string>();
if (script_id.StartsWith("dotnet://"))
{
var dbgUrl = args["dotNetUrl"]?.Value<string>();
var arrStr = dbgUrl.Split("/");
dbgUrl = arrStr[0] + "/" + arrStr[1] + "/" + arrStr[2] + "/" + arrStr[arrStr.Length - 1];
dicScriptsIdToUrl[script_id] = dbgUrl;
dicFileToUrl[dbgUrl] = args["url"]?.Value<string>();
}
else if (!String.IsNullOrEmpty(url))
{
var dbgUrl = args["url"]?.Value<string>();
var arrStr = dbgUrl.Split("/");
dicScriptsIdToUrl[script_id] = arrStr[arrStr.Length - 1];
dicFileToUrl[new Uri(url).AbsolutePath] = url;
}
await Task.FromResult(0);
});
insp.On("Debugger.scriptParsed", DefaultScriptParsedHandler);
return dicScriptsIdToUrl;
}

protected Task<ProtocolEventHandlerReturn> DefaultScriptParsedHandler(JObject args, CancellationToken token)
{
var script_id = args?["scriptId"]?.Value<string>();
var url = args["url"]?.Value<string>();
if (script_id.StartsWith("dotnet://"))
{
var dbgUrl = args["dotNetUrl"]?.Value<string>();
var arrStr = dbgUrl.Split("/");
dbgUrl = arrStr[0] + "/" + arrStr[1] + "/" + arrStr[2] + "/" + arrStr[arrStr.Length - 1];
dicScriptsIdToUrl[script_id] = dbgUrl;
dicFileToUrl[dbgUrl] = args["url"]?.Value<string>();
}
else if (!String.IsNullOrEmpty(url))
{
var dbgUrl = args["url"]?.Value<string>();
var arrStr = dbgUrl.Split("/");
dicScriptsIdToUrl[script_id] = arrStr[arrStr.Length - 1];
dicFileToUrl[new Uri(url).AbsolutePath] = url;
}
return Task.FromResult(ProtocolEventHandlerReturn.KeepHandler);
}

internal async Task CheckInspectLocalsAtBreakpointSite(string url_key, int line, int column, string function_name, string eval_expression,
Func<JToken, Task> test_fn = null, Func<JObject, Task> wait_for_event_fn = null, bool use_cfo = false)
{
Expand Down Expand Up @@ -228,6 +230,47 @@ internal virtual async Task<JObject> WaitFor(string what)
return await insp.WaitFor(what);
}

public async Task WaitForScriptParsedEventsAsync(params string[] paths)
{
object llock = new();
List<string> pathsList = new(paths);
var tcs = new TaskCompletionSource();
insp.On("Debugger.scriptParsed", async (args, c) =>
{
await DefaultScriptParsedHandler(args, c);

string url = args["url"]?.Value<string>();
if (string.IsNullOrEmpty(url))
return await Task.FromResult(ProtocolEventHandlerReturn.KeepHandler);

lock (llock)
{
try
{
int idx = pathsList.FindIndex(p => url?.EndsWith(p) == true);
if (idx >= 0)
{
pathsList.RemoveAt(idx);
if (pathsList.Count == 0)
{
tcs.SetResult();
}
}
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}

return tcs.Task.IsCompleted
? await Task.FromResult(ProtocolEventHandlerReturn.RemoveHandler)
: await Task.FromResult(ProtocolEventHandlerReturn.KeepHandler);
});

await tcs.Task;
}

// sets breakpoint by method name and line offset
internal async Task CheckInspectLocalsAtBreakpointSite(string type, string method, int line_offset, string bp_function_name, string eval_expression,
Func<JToken, Task> locals_fn = null, Func<JObject, Task> wait_for_event_fn = null, bool use_cfo = false, string assembly = "debugger-test.dll", int col = 0)
Expand Down Expand Up @@ -1244,7 +1287,7 @@ internal async Task LoadAssemblyDynamically(string asm_file, string pdb_file)
});

Result load_assemblies_res = await cli.SendCommand("Runtime.evaluate", load_assemblies, token);
Assert.True(load_assemblies_res.IsOk);
load_assemblies_res.AssertOk();
}

internal async Task<JObject> LoadAssemblyDynamicallyALCAndRunMethod(string asm_file, string pdb_file, string type_name, string method_name)
Expand All @@ -1267,8 +1310,7 @@ internal async Task<JObject> LoadAssemblyDynamicallyALCAndRunMethod(string asm_f
});

Result load_assemblies_res = await cli.SendCommand("Runtime.evaluate", load_assemblies, token);

Assert.True(load_assemblies_res.IsOk);
load_assemblies_res.AssertOk();
await bpResolved;

var run_method = JObject.FromObject(new
Expand All @@ -1280,7 +1322,7 @@ internal async Task<JObject> LoadAssemblyDynamicallyALCAndRunMethod(string asm_f
return await WaitFor(Inspector.PAUSE);
}

internal async Task<JObject> LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges(string asm_file, string pdb_file, string class_name, string method_name)
internal async Task<JObject> LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges(string asm_file, string pdb_file, string class_name, string method_name, bool expectBpResolvedEvent)
{
byte[] bytes = File.ReadAllBytes(asm_file);
string asm_base64 = Convert.ToBase64String(bytes);
Expand All @@ -1294,15 +1336,18 @@ internal async Task<JObject> LoadAssemblyAndTestHotReloadUsingSDBWithoutChanges(
expression
});

Result load_assemblies_res = await cli.SendCommand("Runtime.evaluate", load_assemblies, token);
Task eventTask = expectBpResolvedEvent
? WaitForBreakpointResolvedEvent()
: WaitForScriptParsedEventsAsync("MethodBody0.cs", "MethodBody1.cs");
(await cli.SendCommand("Runtime.evaluate", load_assemblies, token)).AssertOk();
await eventTask;

Thread.Sleep(1000);
var run_method = JObject.FromObject(new
{
expression = "window.setTimeout(function() { invoke_static_method('[debugger-test] TestHotReloadUsingSDB:RunMethod', '" + class_name + "', '" + method_name + "'); }, 1);"
});

await cli.SendCommand("Runtime.evaluate", run_method, token);
(await cli.SendCommand("Runtime.evaluate", run_method, token)).AssertOk();
return await WaitFor(Inspector.PAUSE);
}

Expand Down Expand Up @@ -1352,7 +1397,7 @@ internal async Task<JObject> LoadAssemblyAndTestHotReloadUsingSDB(string asm_fil
return await WaitFor(Inspector.PAUSE);
}

internal async Task<JObject> LoadAssemblyAndTestHotReload(string asm_file, string pdb_file, string asm_file_hot_reload, string class_name, string method_name)
internal async Task<JObject> LoadAssemblyAndTestHotReload(string asm_file, string pdb_file, string asm_file_hot_reload, string class_name, string method_name, bool expectBpResolvedEvent)
{
byte[] bytes = File.ReadAllBytes(asm_file);
string asm_base64 = Convert.ToBase64String(bytes);
Expand Down Expand Up @@ -1387,10 +1432,12 @@ internal async Task<JObject> LoadAssemblyAndTestHotReload(string asm_file, strin
expression
});

Result load_assemblies_res = await cli.SendCommand("Runtime.evaluate", load_assemblies, token);
Task eventTask = expectBpResolvedEvent
? WaitForBreakpointResolvedEvent()
: WaitForScriptParsedEventsAsync("MethodBody0.cs", "MethodBody1.cs");
(await cli.SendCommand("Runtime.evaluate", load_assemblies, token)).AssertOk();
await eventTask;

Assert.True(load_assemblies_res.IsOk);
Thread.Sleep(1000);
var run_method = JObject.FromObject(new
{
expression = "window.setTimeout(function() { invoke_static_method('[debugger-test] TestHotReload:RunMethod', '" + class_name + "', '" + method_name + "'); }, 1);"
Expand All @@ -1416,7 +1463,7 @@ public async Task<JObject> WaitForBreakpointResolvedEvent()

internal async Task SetJustMyCode(bool enabled)
{
var req = JObject.FromObject(new { enabled = enabled });
var req = JObject.FromObject(new { enabled });
var res = await cli.SendCommand("DotnetDebugger.justMyCode", req, token);
Assert.True(res.IsOk);
Assert.Equal(res.Value["justMyCodeEnabled"], enabled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ internal override Dictionary<string, string> SubscribeToScripts(Inspector insp)
dicScriptsIdToUrl[script_id] = arrStr[arrStr.Length - 1];
dicFileToUrl[new Uri(url).AbsolutePath] = url;
}
await Task.FromResult(0);
return await Task.FromResult(ProtocolEventHandlerReturn.KeepHandler);
});
insp.On("resource-available-form", async (args, c) =>
{
Expand All @@ -86,7 +86,7 @@ internal override Dictionary<string, string> SubscribeToScripts(Inspector insp)
dicScriptsIdToUrl[script_id] = arrStr[arrStr.Length - 1];
dicFileToUrl[new Uri(url).AbsolutePath] = url;
}
await Task.FromResult(0);
return await Task.FromResult(ProtocolEventHandlerReturn.KeepHandler);
});
return dicScriptsIdToUrl;
}
Expand Down
Loading