Skip to content

Commit

Permalink
[wasm][debugger] Fix hang in ArrayTests (#63528)
Browse files Browse the repository at this point in the history
There were some instances of async calls being blocking by the use of
`.Wait()` on the task, in various `Check*` methods. And that would cause
completions to get blocked, and not get run.

In some cases, we didn't await the task at all, and so failures in that
would only fail randomly.

This removes all uses of `.Wait()`, and makes the methods async, and
correctly awaits on them.

Fixes #62661 .
  • Loading branch information
radical authored Jan 10, 2022
1 parent c92c767 commit f9a1c78
Show file tree
Hide file tree
Showing 13 changed files with 157 additions and 156 deletions.
18 changes: 9 additions & 9 deletions src/mono/wasm/debugger/BrowserDebugProxy/DevToolsProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ public async Task Run(Uri browserUri, WebSocket ideSocket)
{
while (!x.IsCancellationRequested)
{
Task task = await Task.WhenAny(pending_ops.ToArray());
Task completedTask = await Task.WhenAny(pending_ops.ToArray());

if (client_initiated_close.Task.IsCompleted)
{
Expand All @@ -280,34 +280,34 @@ public async Task Run(Uri browserUri, WebSocket ideSocket)
}

//logger.LogTrace ("pump {0} {1}", task, pending_ops.IndexOf (task));
if (task == pending_ops[0])
if (completedTask == pending_ops[0])
{
string msg = ((Task<string>)task).Result;
string msg = ((Task<string>)completedTask).Result;
if (msg != null)
{
pending_ops[0] = ReadOne(browser, x.Token); //queue next read
ProcessBrowserMessage(msg, x.Token);
}
}
else if (task == pending_ops[1])
else if (completedTask == pending_ops[1])
{
string msg = ((Task<string>)task).Result;
string msg = ((Task<string>)completedTask).Result;
if (msg != null)
{
pending_ops[1] = ReadOne(ide, x.Token); //queue next read
ProcessIdeMessage(msg, x.Token);
}
}
else if (task == pending_ops[2])
else if (completedTask == pending_ops[2])
{
bool res = ((Task<bool>)task).Result;
bool res = ((Task<bool>)completedTask).Result;
throw new Exception("side task must always complete with an exception, what's going on???");
}
else
{
//must be a background task
pending_ops.Remove(task);
DevToolsQueue queue = GetQueueForTask(task);
pending_ops.Remove(completedTask);
DevToolsQueue queue = GetQueueForTask(completedTask);
if (queue != null)
{
if (queue.TryPumpIfCurrentCompleted(x.Token, out Task tsk))
Expand Down
53 changes: 30 additions & 23 deletions src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@

namespace DebuggerTests
{
// https://github.com/dotnet/runtime/issues/62661
[Trait("Category", "windows-failing")]
[Trait("Category", "linux-failing")]
public class ArrayTests : DebuggerTestBase
{

Expand Down Expand Up @@ -234,10 +231,10 @@ async Task TestSimpleArrayLocals(int line, int col, string entry_method_name, st

var locals = await GetProperties(pause_location["callFrames"][frame_idx]["callFrameId"].Value<string>());
Assert.Equal(4, locals.Count());
CheckArray(locals, $"{local_var_name_prefix}_arr", $"{etype_name}[]", $"{etype_name}[{array?.Length ?? 0}]");
CheckArray(locals, $"{local_var_name_prefix}_arr_empty", $"{etype_name}[]", $"{etype_name}[0]");
CheckObject(locals, $"{local_var_name_prefix}_arr_null", $"{etype_name}[]", is_null: true);
CheckBool(locals, "call_other", test_prev_frame);
await CheckArray(locals, $"{local_var_name_prefix}_arr", $"{etype_name}[]", $"{etype_name}[{array?.Length ?? 0}]");
await CheckArray(locals, $"{local_var_name_prefix}_arr_empty", $"{etype_name}[]", $"{etype_name}[0]");
await CheckObject(locals, $"{local_var_name_prefix}_arr_null", $"{etype_name}[]", is_null: true);
await CheckBool(locals, "call_other", test_prev_frame);

var local_arr_name = $"{local_var_name_prefix}_arr";

Expand Down Expand Up @@ -308,7 +305,7 @@ public async Task InspectObjectArrayMembers(bool use_cfo)
var pause_location = await EvaluateAndCheck(eval_expr, debugger_test_loc, line, col, method_name);
var locals = await GetProperties(pause_location["callFrames"][frame_idx]["callFrameId"].Value<string>());
Assert.Single(locals);
CheckObject(locals, "c", "DebuggerTests.Container");
await CheckObject(locals, "c", "DebuggerTests.Container");

var c_props = await GetObjectOnFrame(pause_location["callFrames"][frame_idx], "c");
await CheckProps(c_props, new
Expand Down Expand Up @@ -554,6 +551,7 @@ await CompareObjectPropertiesFor(frame_locals, "this",
label: "this#0");
}

#if false // https://github.com/dotnet/runtime/issues/63560
[Fact]
public async Task InvalidArrayId() => await CheckInspectLocalsAtBreakpointSite(
"DebuggerTests.Container", "PlaceholderMethod", 1, "PlaceholderMethod",
Expand Down Expand Up @@ -619,31 +617,40 @@ public async Task InvalidValueTypeArrayIndex() => await CheckInspectLocalsAtBrea
id_args["arrayIdx"] = "qwe";
await GetProperties($"dotnet:valuetype:{id_args.ToString(Newtonsoft.Json.Formatting.None)}", expect_ok: false);
});
#endif

[Fact]
public async Task InvalidAccessors() => await CheckInspectLocalsAtBreakpointSite(
"DebuggerTests.Container", "PlaceholderMethod", 1, "PlaceholderMethod",
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.ArrayTestsClass:ObjectArrayMembers'); }, 1);",
locals_fn: async (locals) =>
{
var this_obj = GetAndAssertObjectWithName(locals, "this");
var c_obj = GetAndAssertObjectWithName(await GetProperties(this_obj["value"]["objectId"].Value<string>()), "c");
var c_obj_id = c_obj["value"]?["objectId"]?.Value<string>();
Assert.NotNull(c_obj_id);
{
var this_obj = GetAndAssertObjectWithName(locals, "this");
var this_obj_id = this_obj["value"]?["objectId"]?.Value<string>();
Assert.NotNull(this_obj_id);

var c_props = await GetProperties(c_obj_id);
var this_props = await GetProperties(this_obj_id);

var pf_arr = GetAndAssertObjectWithName(c_props, "PointsField");
var pf_arr = GetAndAssertObjectWithName(this_props, "PointsField");

// Validate the way we test the accessors, with a valid one
var res = await InvokeGetter(pf_arr, "0", expect_ok: true);
await CheckValue(res.Value["result"], TValueType("DebuggerTests.Point"), "pf_arr[0]");
var pf_arr0_props = await GetProperties(res.Value["result"]["objectId"]?.Value<string>());
await CheckProps(pf_arr0_props, new
{
X = TNumber(5)
}, "pf_arr0_props", num_fields: 4);

var invalid_accessors = new object[] { "NonExistant", "10000", "-2", 10000, -2, null, String.Empty };
foreach (var invalid_accessor in invalid_accessors)
{
// var res = await InvokeGetter (JObject.FromObject (new { value = new { objectId = obj_id } }), invalid_accessor, expect_ok: true);
var res = await InvokeGetter(pf_arr, invalid_accessor, expect_ok: true);
AssertEqual("undefined", res.Value["result"]?["type"]?.ToString(), "Expected to get undefined result for non-existant accessor");
}
var invalid_accessors = new object[] { "NonExistant", "10000", "-2", 10000, -2, null, String.Empty };
foreach (var invalid_accessor in invalid_accessors)
{
// var res = await InvokeGetter (JObject.FromObject (new { value = new { objectId = obj_id } }), invalid_accessor, expect_ok: true);
res = await InvokeGetter(pf_arr, invalid_accessor, expect_ok: true);
AssertEqual("undefined", res.Value["result"]?["type"]?.ToString(), "Expected to get undefined result for non-existant accessor");
}
});

[Theory]
[InlineData(false)]
[InlineData(true)]
Expand Down
4 changes: 2 additions & 2 deletions src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ await StepAndCheck(StepKind.Into, "dotnet://debugger-test.dll/debugger-assignmen
locals_fn: async (locals) =>
{
Assert.Equal(2, locals.Count());
Check(locals, "r", checkDefault);
await Check(locals, "r", checkDefault);
await Task.CompletedTask;
}
);
Expand All @@ -59,7 +59,7 @@ await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-assignmen
locals_fn: async (locals) =>
{
Assert.Equal(2, locals.Count());
Check(locals, "r", checkValue);
await Check(locals, "r", checkValue);
await Task.CompletedTask;
}
);
Expand Down
4 changes: 2 additions & 2 deletions src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ public async Task DebugHotReloadMethodChangedUserBreak()
CheckNumber(locals, "b", 15);
pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 12, 12, "StaticMethod1");
locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value<string>());
CheckBool(locals, "c", true);
await CheckBool(locals, "c", true);
}

[Fact]
Expand Down Expand Up @@ -374,7 +374,7 @@ public async Task DebugHotReloadMethodAddBreakpoint()

pause_location = await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 30, 12, "StaticMethod3");
locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value<string>());
CheckBool(locals, "c", true);
await CheckBool(locals, "c", true);

await StepAndCheck(StepKind.Over, "dotnet://ApplyUpdateReferencedAssembly.dll/MethodBody1.cs", 31, 12, "StaticMethod3",
locals_fn: async (locals) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public async Task RunOnVTArray(bool roundtrip) => await RunCallFunctionOn(

for (int i = 0; i < ret_len; i++)
{
var act_i = CheckValueType(obj_own_val, i.ToString(), "Math.SimpleStruct");
var act_i = await CheckValueType(obj_own_val, i.ToString(), "Math.SimpleStruct");

// Valuetypes can get sent as part of the container's getProperties, so ensure that we can access it
var act_i_props = await GetProperties(act_i["value"]["objectId"]?.Value<string>());
Expand Down
22 changes: 12 additions & 10 deletions src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public async Task UsingDebuggerDisplay()
"run");

var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value<string>());
CheckObject(locals, "a", "DebuggerTests.WithDisplayString", description:"Some one Value 2 End");
CheckObject(locals, "c", "DebuggerTests.DebuggerDisplayMethodTest", description: "First Int:32 Second Int:43");
CheckObject(locals, "myList", "System.Collections.Generic.List<int>", description: "Count = 4");
CheckObject(locals, "person1", "DebuggerTests.Person", description: "FirstName: Anton, SurName: Mueller, Age: 44");
CheckObject(locals, "person2", "DebuggerTests.Person", description: "FirstName: Lisa, SurName: Müller, Age: 41");
await CheckObject(locals, "a", "DebuggerTests.WithDisplayString", description:"Some one Value 2 End");
await CheckObject(locals, "c", "DebuggerTests.DebuggerDisplayMethodTest", description: "First Int:32 Second Int:43");
await CheckObject(locals, "myList", "System.Collections.Generic.List<int>", description: "Count = 4");
await CheckObject(locals, "person1", "DebuggerTests.Person", description: "FirstName: Anton, SurName: Mueller, Age: 44");
await CheckObject(locals, "person2", "DebuggerTests.Person", description: "FirstName: Lisa, SurName: Müller, Age: 41");
}

[Fact]
Expand All @@ -47,17 +47,17 @@ public async Task UsingDebuggerTypeProxy()

var frame = pause_location["callFrames"][0];
var locals = await GetProperties(frame["callFrameId"].Value<string>());
CheckObject(locals, "myList", "System.Collections.Generic.List<int>", description: "Count = 4");
await CheckObject(locals, "myList", "System.Collections.Generic.List<int>", description: "Count = 4");
var props = await GetObjectOnFrame(frame, "myList");
Assert.Equal(1, props.Count());

CheckArray(props, "Items", "int[]", "int[4]");
await CheckArray(props, "Items", "int[]", "int[4]");

CheckObject(locals, "b", "DebuggerTests.WithProxy", description:"DebuggerTests.WithProxy");
await CheckObject(locals, "b", "DebuggerTests.WithProxy", description:"DebuggerTests.WithProxy");
props = await GetObjectOnFrame(frame, "b");
CheckString(props, "Val2", "one");
await CheckString(props, "Val2", "one");

CheckObject(locals, "openWith", "System.Collections.Generic.Dictionary<string, string>", description: "Count = 3");
await CheckObject(locals, "openWith", "System.Collections.Generic.Dictionary<string, string>", description: "Count = 3");
props = await GetObjectOnFrame(frame, "openWith");
Assert.Equal(1, props.Count());

Expand Down Expand Up @@ -95,8 +95,10 @@ async Task<bool> CheckProperties(JObject pause_location)
var task = CheckProperties(pause_location);
tasks.Add(task);
}
await Task.WhenAll(tasks);
foreach(Task<bool> task in tasks)
{
//FIXME: blocks
Assert.True(task.Result);
}
}
Expand Down
Loading

0 comments on commit f9a1c78

Please sign in to comment.