Skip to content

Commit 9d10ec7

Browse files
author
Anna Gringauze
authored
Make dwds more conformant to vm_service protocol (#1370)
* Make dwds conform to vm service protocol - Throw SentiinelException if the isolate id is unrecognized - Throw RPCError if getStack is called when not paused - Fix race conditions in chrome_proxy_tests Helps: #1369 Closes: #721 * Update version and changelog * Build * Addressed CR comments
1 parent 9fa1d54 commit 9d10ec7

File tree

8 files changed

+4911
-4805
lines changed

8 files changed

+4911
-4805
lines changed

dwds/CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
## 11.1.2
1+
## 11.2.0-dev
2+
3+
- Throw `SentinelException` instead of `RPCError` on vm service
4+
API on unrecognized isolate.
5+
- Throw `RPCError` in `getStack` if the application is not paused.
6+
- Recognize `dart:ui` library when debugging flutter apps.
7+
- Fix hang on hot restart when the application has a breakpoint.
28

9+
## 11.1.2
310
- Return empty library from `ChromeProxyService.getObject` for
411
libraries present in medatata but not loaded at runtime.
512
- Log failures to load kernel during expression evaluation.

dwds/lib/src/debugging/debugger.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import 'dart:math' as math;
99

1010
import 'package:logging/logging.dart';
1111
import 'package:meta/meta.dart';
12-
import 'package:vm_service/vm_service.dart' as vm_service;
1312
import 'package:vm_service/vm_service.dart';
1413
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
1514
hide StackTrace;
@@ -148,7 +147,11 @@ class Debugger extends Domain {
148147
/// The returned stack will contain up to [limit] frames if provided.
149148
Future<Stack> getStack(String isolateId, {int limit}) async {
150149
checkIsolate('getStack', isolateId);
151-
if (stackComputer == null) return null;
150+
151+
if (stackComputer == null) {
152+
throw RPCError('getStack', RPCError.kInternalError,
153+
'Cannot compute stack when application is not paused');
154+
}
152155

153156
var frames = await stackComputer.calculateFrames(limit: limit);
154157
return Stack(
@@ -324,8 +327,7 @@ class Debugger extends Domain {
324327
// Filter out variables that do not come from dart code, such as native
325328
// JavaScript objects
326329
return boundVariables
327-
.where((bv) =>
328-
bv != null && !isNativeJsObject(bv.value as vm_service.InstanceRef))
330+
.where((bv) => bv != null && !isNativeJsObject(bv.value as InstanceRef))
329331
.toList();
330332
}
331333

@@ -631,7 +633,7 @@ class Debugger extends Domain {
631633
}
632634
}
633635

634-
bool isNativeJsObject(vm_service.InstanceRef instanceRef) =>
636+
bool isNativeJsObject(InstanceRef instanceRef) =>
635637
// New type representation of JS objects reifies them to JavaScriptObject.
636638
(instanceRef?.classRef?.name == 'JavaScriptObject' &&
637639
instanceRef?.classRef?.library?.uri == 'dart:_interceptors') ||

dwds/lib/src/injected/client.js

Lines changed: 4813 additions & 4734 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dwds/lib/src/utilities/domain.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ abstract class Domain {
3232
/// isolate id.
3333
Isolate checkIsolate(String methodName, String isolateId) {
3434
if (isolateId != inspector.isolate?.id) {
35-
throwInvalidParam(methodName, 'Unrecognized isolateId: $isolateId');
35+
throwSentinel(methodName, SentinelKind.kCollected,
36+
'Unrecognized isolateId: $isolateId');
3637
}
3738
return inspector.isolate;
3839
}
@@ -41,4 +42,10 @@ abstract class Domain {
4142
void throwInvalidParam(String method, String message) {
4243
throw RPCError(method, RPCError.kInvalidParams, message);
4344
}
45+
46+
@alwaysThrows
47+
void throwSentinel(String method, String kind, String message) {
48+
var data = <String, String>{'kind': kind, 'valueAsString': message};
49+
throw SentinelException.parse(method, data);
50+
}
4451
}

dwds/lib/src/version.dart

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dwds/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: dwds
22
# Every time this changes you need to run `pub run build_runner build`.
3-
version: 11.1.2
3+
version: 11.2.0-dev
44
homepage: https://github.com/dart-lang/webdev/tree/master/dwds
55
description: >-
66
A service that proxies between the Chrome debug protocol and the Dart VM

dwds/test/chrome_proxy_service_test.dart

Lines changed: 71 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ void main() {
107107
expect(bp.id, isNotNull);
108108
});
109109

110-
test('addBreakpointAtEntry', () {
111-
expect(() => service.addBreakpointAtEntry(null, null), throwsRPCError);
110+
test('addBreakpointAtEntry', () async {
111+
await expectLater(
112+
service.addBreakpointAtEntry(null, null), throwsRPCError);
112113
});
113114

114115
test('addBreakpointWithScriptUri', () async {
@@ -136,13 +137,16 @@ void main() {
136137
expect(bp.id, isNotNull);
137138
});
138139

139-
test('removeBreakpoint null arguments', () {
140-
expect(() => service.removeBreakpoint(null, null), throwsRPCError);
140+
test('removeBreakpoint null arguments', () async {
141+
await expectLater(
142+
service.removeBreakpoint(null, null), throwsSentinelException);
143+
await expectLater(
144+
service.removeBreakpoint(isolate.id, null), throwsRPCError);
141145
});
142146

143-
test("removeBreakpoint that doesn't exist fails", () {
144-
expect(
145-
() => service.removeBreakpoint(isolate.id, '1234'), throwsRPCError);
147+
test("removeBreakpoint that doesn't exist fails", () async {
148+
await expectLater(
149+
service.removeBreakpoint(isolate.id, '1234'), throwsRPCError);
146150
});
147151

148152
test('add and remove breakpoint', () async {
@@ -204,24 +208,24 @@ void main() {
204208
});
205209

206210
group('VMTimeline', () {
207-
test('clearVMTimeline', () {
208-
expect(() => service.clearVMTimeline(), throwsRPCError);
211+
test('clearVMTimeline', () async {
212+
await expectLater(service.clearVMTimeline(), throwsRPCError);
209213
});
210214

211-
test('getVMTimelineMicros', () {
212-
expect(() => service.getVMTimelineMicros(), throwsRPCError);
215+
test('getVMTimelineMicros', () async {
216+
await expectLater(service.getVMTimelineMicros(), throwsRPCError);
213217
});
214218

215-
test('getVMTimeline', () {
216-
expect(() => service.getVMTimeline(), throwsRPCError);
219+
test('getVMTimeline', () async {
220+
await expectLater(service.getVMTimeline(), throwsRPCError);
217221
});
218222

219-
test('getVMTimelineFlags', () {
220-
expect(() => service.getVMTimelineFlags(), throwsRPCError);
223+
test('getVMTimelineFlags', () async {
224+
await expectLater(service.getVMTimelineFlags(), throwsRPCError);
221225
});
222226

223-
test('setVMTimelineFlags', () {
224-
expect(() => service.setVMTimelineFlags(null), throwsRPCError);
227+
test('setVMTimelineFlags', () async {
228+
await expectLater(service.setVMTimelineFlags(null), throwsRPCError);
225229
});
226230
});
227231

@@ -336,24 +340,25 @@ void main() {
336340
});
337341
});
338342

339-
test('evaluateInFrame', () {
340-
expect(() => service.evaluateInFrame(null, null, null), throwsRPCError);
343+
test('evaluateInFrame', () async {
344+
await expectLater(
345+
service.evaluateInFrame(null, null, null), throwsRPCError);
341346
});
342347

343-
test('getAllocationProfile', () {
344-
expect(() => service.getAllocationProfile(null), throwsRPCError);
348+
test('getAllocationProfile', () async {
349+
await expectLater(service.getAllocationProfile(null), throwsRPCError);
345350
});
346351

347-
test('getClassList', () {
348-
expect(() => service.getClassList(null), throwsRPCError);
352+
test('getClassList', () async {
353+
await expectLater(service.getClassList(null), throwsRPCError);
349354
});
350355

351356
test('getFlagList', () async {
352357
expect(await service.getFlagList(), isA<FlagList>());
353358
});
354359

355-
test('getInstances', () {
356-
expect(() => service.getInstances(null, null, null), throwsRPCError);
360+
test('getInstances', () async {
361+
await expectLater(service.getInstances(null, null, null), throwsRPCError);
357362
});
358363

359364
group('getIsolate', () {
@@ -653,16 +658,16 @@ void main() {
653658
var vm = await service.getVM();
654659
var isolateId = vm.isolates.first.id;
655660

656-
expect(() => service.getSourceReport(isolateId, ['Coverage']),
657-
throwsRPCError);
661+
await expectLater(
662+
service.getSourceReport(isolateId, ['Coverage']), throwsRPCError);
658663
});
659664

660665
test('report type not understood', () async {
661666
var vm = await service.getVM();
662667
var isolateId = vm.isolates.first.id;
663668

664-
expect(() => service.getSourceReport(isolateId, ['FooBar']),
665-
throwsRPCError);
669+
await expectLater(
670+
service.getSourceReport(isolateId, ['FooBar']), throwsRPCError);
666671
});
667672

668673
test('PossibleBreakpoints report', () async {
@@ -804,25 +809,28 @@ void main() {
804809
.firstWhere((each) => each.uri.contains('main.dart'));
805810
});
806811

807-
test('returns null if not paused', () async {
808-
expect(await service.getStack(isolateId), isNull);
809-
}, onPlatform: {'windows': const Skip('issues/721')});
812+
test('throws if not paused', () async {
813+
await expectLater(service.getStack(isolateId), throwsRPCError);
814+
});
810815

811816
/// Support function for pausing and returning the stack at a line.
812817
Future<Stack> breakAt(String breakpointId, {int limit}) async {
813-
var lineNumber = await context.findBreakpointLine(
818+
var line = await context.findBreakpointLine(
814819
breakpointId, isolateId, mainScript);
815-
var bp =
816-
await service.addBreakpoint(isolateId, mainScript.id, lineNumber);
817-
// Wait for breakpoint to trigger.
818-
await stream
819-
.firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
820-
// Remove breakpoint so it doesn't impact other tests.
821-
await service.removeBreakpoint(isolateId, bp.id);
822-
var stack = await service.getStack(isolateId, limit: limit);
823-
// Resume as to not impact other tests.
824-
await service.resume(isolateId);
825-
return stack;
820+
Breakpoint bp;
821+
try {
822+
bp = await service.addBreakpoint(isolateId, mainScript.id, line);
823+
// Wait for breakpoint to trigger.
824+
await stream
825+
.firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
826+
return await service.getStack(isolateId, limit: limit);
827+
} finally {
828+
// Remove breakpoint and resume so it doesn't impact other tests.
829+
if (bp != null) {
830+
await service.removeBreakpoint(isolateId, bp.id);
831+
}
832+
await service.resume(isolateId);
833+
}
826834
}
827835

828836
test('returns stack when broken', () async {
@@ -1048,11 +1056,11 @@ void main() {
10481056
});
10491057
});
10501058

1051-
test('kill', () {
1052-
expect(() => service.kill(null), throwsRPCError);
1059+
test('kill', () async {
1060+
await expectLater(service.kill(null), throwsRPCError);
10531061
});
10541062

1055-
test('onEvent', () {
1063+
test('onEvent', () async {
10561064
expect(() => service.onEvent(null), throwsRPCError);
10571065
});
10581066

@@ -1085,21 +1093,22 @@ void main() {
10851093
});
10861094

10871095
test('getInboundReferences', () async {
1088-
expect(
1089-
() => service.getInboundReferences(null, null, null), throwsRPCError);
1096+
await expectLater(
1097+
service.getInboundReferences(null, null, null), throwsRPCError);
10901098
});
10911099

10921100
test('getRetainingPath', () async {
1093-
expect(() => service.getRetainingPath(null, null, null), throwsRPCError);
1101+
await expectLater(
1102+
service.getRetainingPath(null, null, null), throwsRPCError);
10941103
});
10951104

10961105
test('registerService', () async {
1097-
expect(
1098-
() => service.registerService('ext.foo.bar', null), throwsRPCError);
1106+
await expectLater(
1107+
service.registerService('ext.foo.bar', null), throwsRPCError);
10991108
});
11001109

1101-
test('reloadSources', () {
1102-
expect(() => service.reloadSources(null), throwsRPCError);
1110+
test('reloadSources', () async {
1111+
await expectLater(service.reloadSources(null), throwsRPCError);
11031112
});
11041113

11051114
test('setExceptionPauseMode', () async {
@@ -1111,17 +1120,17 @@ void main() {
11111120
// Make sure this is the last one - or future tests might hang.
11121121
expect(
11131122
await service.setExceptionPauseMode(isolateId, 'none'), _isSuccess);
1114-
expect(
1123+
await expectLater(
11151124
service.setExceptionPauseMode(isolateId, 'invalid'), throwsRPCError);
11161125
});
11171126

1118-
test('setFlag', () {
1119-
expect(() => service.setFlag(null, null), throwsRPCError);
1127+
test('setFlag', () async {
1128+
await expectLater(service.setFlag(null, null), throwsRPCError);
11201129
});
11211130

1122-
test('setLibraryDebuggable', () {
1123-
expect(
1124-
() => service.setLibraryDebuggable(null, null, null), throwsRPCError);
1131+
test('setLibraryDebuggable', () async {
1132+
await expectLater(
1133+
service.setLibraryDebuggable(null, null, null), throwsRPCError);
11251134
});
11261135

11271136
test('setName', () async {
@@ -1138,8 +1147,8 @@ void main() {
11381147
expect(vm.name, 'foo');
11391148
});
11401149

1141-
test('streamCancel', () {
1142-
expect(() => service.streamCancel(null), throwsRPCError);
1150+
test('streamCancel', () async {
1151+
await expectLater(service.streamCancel(null), throwsRPCError);
11431152
});
11441153

11451154
group('streamListen/onEvent', () {

dwds/test/fixtures/context.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ final _batExt = Platform.isWindows ? '.bat' : '';
3636
final _exeExt = Platform.isWindows ? '.exe' : '';
3737

3838
const isRPCError = TypeMatcher<RPCError>();
39+
const isSentinelException = TypeMatcher<SentinelException>();
3940

4041
final Matcher throwsRPCError = throwsA(isRPCError);
42+
final Matcher throwsSentinelException = throwsA(isSentinelException);
4143

4244
enum CompilationMode { buildDaemon, frontendServer }
4345

0 commit comments

Comments
 (0)