[ package:vm_service ] 4.0.0 release, Sentinels are now thrown, Future<dynamic> returns are now Future<Response>
Change-Id: Ifd1bf62e3bc33bf14359802086c87b2fd19f3ba9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138561
Reviewed-by: Jacob Richman <jacobr@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 2041a96..6758942 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,7 +1,14 @@
# Changelog
+## 4.0.0
+- **breaking**: RPCs which can return a `Sentinel` will now throw the `Sentinel`
+ it is received as a response.
+- **breaking**: RPCs which can return multiple values now return
+ `Future<Response>` rather than `Future<dynamic>`.
+- `RPCError` now implements `Exception`.
+
## 3.0.0
-**breaking**: RPCs which have an isolateId parameter now return
+- **breaking**: RPCs which have an isolateId parameter now return
`Future<dynamic>` as a `Sentinel` can be returned if the target isolate no
longer exists.
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index 0a689b9..7fc8e94 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -185,47 +185,47 @@
};
Map<String, List<String>> _methodReturnTypes = {
- 'addBreakpoint': const ['Breakpoint', 'Sentinel'],
- 'addBreakpointWithScriptUri': const ['Breakpoint', 'Sentinel'],
- 'addBreakpointAtEntry': const ['Breakpoint', 'Sentinel'],
- 'clearCpuSamples': const ['Success', 'Sentinel'],
+ 'addBreakpoint': const ['Breakpoint'],
+ 'addBreakpointWithScriptUri': const ['Breakpoint'],
+ 'addBreakpointAtEntry': const ['Breakpoint'],
+ 'clearCpuSamples': const ['Success'],
'clearVMTimeline': const ['Success'],
- 'invoke': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
- 'evaluate': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
- 'evaluateInFrame': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
- 'getAllocationProfile': const ['AllocationProfile', 'Sentinel'],
+ 'invoke': const ['InstanceRef', 'ErrorRef'],
+ 'evaluate': const ['InstanceRef', 'ErrorRef'],
+ 'evaluateInFrame': const ['InstanceRef', 'ErrorRef'],
+ 'getAllocationProfile': const ['AllocationProfile'],
'getClientName': const ['ClientName'],
- 'getCpuSamples': const ['CpuSamples', 'Sentinel'],
+ 'getCpuSamples': const ['CpuSamples'],
'getFlagList': const ['FlagList'],
- 'getInboundReferences': const ['InboundReferences', 'Sentinel'],
- 'getInstances': const ['InstanceSet', 'Sentinel'],
- 'getIsolate': const ['Isolate', 'Sentinel'],
- 'getIsolateGroup': const ['IsolateGroup', 'Sentinel'],
- 'getMemoryUsage': const ['MemoryUsage', 'Sentinel'],
- 'getIsolateGroupMemoryUsage': const ['MemoryUsage', 'Sentinel'],
- 'getScripts': const ['ScriptList', 'Sentinel'],
- 'getObject': const ['Obj', 'Sentinel'],
- 'getRetainingPath': const ['RetainingPath', 'Sentinel'],
- 'getStack': const ['Stack', 'Sentinel'],
- 'getSourceReport': const ['SourceReport', 'Sentinel'],
+ 'getInboundReferences': const ['InboundReferences'],
+ 'getInstances': const ['InstanceSet'],
+ 'getIsolate': const ['Isolate'],
+ 'getIsolateGroup': const ['IsolateGroup'],
+ 'getMemoryUsage': const ['MemoryUsage'],
+ 'getIsolateGroupMemoryUsage': const ['MemoryUsage'],
+ 'getScripts': const ['ScriptList'],
+ 'getObject': const ['Obj'],
+ 'getRetainingPath': const ['RetainingPath'],
+ 'getStack': const ['Stack'],
+ 'getSourceReport': const ['SourceReport'],
'getVersion': const ['Version'],
'getVM': const ['VM'],
'getVMTimeline': const ['Timeline'],
'getVMTimelineFlags': const ['TimelineFlags'],
'getVMTimelineMicros': const ['Timestamp'],
- 'pause': const ['Success', 'Sentinel'],
- 'kill': const ['Success', 'Sentinel'],
+ 'pause': const ['Success'],
+ 'kill': const ['Success'],
'registerService': const ['Success'],
- 'reloadSources': const ['ReloadReport', 'Sentinel'],
- 'removeBreakpoint': const ['Success', 'Sentinel'],
- 'requestHeapSnapshot': const ['Success', 'Sentinel'],
+ 'reloadSources': const ['ReloadReport'],
+ 'removeBreakpoint': const ['Success'],
+ 'requestHeapSnapshot': const ['Success'],
'requirePermissionToResume': const ['Success'],
- 'resume': const ['Success', 'Sentinel'],
+ 'resume': const ['Success'],
'setClientName': const ['Success'],
- 'setExceptionPauseMode': const ['Success', 'Sentinel'],
+ 'setExceptionPauseMode': const ['Success'],
'setFlag': const ['Success', 'Error'],
- 'setLibraryDebuggable': const ['Success', 'Sentinel'],
- 'setName': const ['Success', 'Sentinel'],
+ 'setLibraryDebuggable': const ['Success'],
+ 'setName': const ['Success'],
'setVMName': const ['Success'],
'setVMTimelineFlags': const ['Success'],
'streamCancel': const ['Success'],
@@ -272,8 +272,9 @@
///
/// See [Breakpoint].
///
- /// The return value can be one of [Breakpoint] or [Sentinel].
- Future<dynamic> addBreakpoint(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Breakpoint> addBreakpoint(
String isolateId,
String scriptId,
int line, {
@@ -308,8 +309,9 @@
///
/// See [Breakpoint].
///
- /// The return value can be one of [Breakpoint] or [Sentinel].
- Future<dynamic> addBreakpointWithScriptUri(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Breakpoint> addBreakpointWithScriptUri(
String isolateId,
String scriptUri,
int line, {
@@ -329,8 +331,9 @@
///
/// Note that breakpoints are added and removed on a per-isolate basis.
///
- /// The return value can be one of [Breakpoint] or [Sentinel].
- Future<dynamic> addBreakpointAtEntry(String isolateId, String functionId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Breakpoint> addBreakpointAtEntry(String isolateId, String functionId);
/// Clears all CPU profiling samples.
///
@@ -339,8 +342,9 @@
///
/// See [Success].
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> clearCpuSamples(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> clearCpuSamples(String isolateId);
/// Clears all VM timeline events.
///
@@ -379,8 +383,11 @@
/// If the invocation is evaluated successfully, an [InstanceRef] reference
/// will be returned.
///
- /// The return value can be one of [InstanceRef], [ErrorRef] or [Sentinel].
- Future<dynamic> invoke(
+ /// The return value can be one of [InstanceRef] or [ErrorRef].
+ ///
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Response> invoke(
String isolateId,
String targetId,
String selector,
@@ -422,8 +429,11 @@
/// If the expression is evaluated successfully, an [InstanceRef] reference
/// will be returned.
///
- /// The return value can be one of [InstanceRef], [ErrorRef] or [Sentinel].
- Future<dynamic> evaluate(
+ /// The return value can be one of [InstanceRef] or [ErrorRef].
+ ///
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Response> evaluate(
String isolateId,
String targetId,
String expression, {
@@ -457,8 +467,11 @@
/// If `isolateId` refers to an isolate which has exited, then the `Collected`
/// [Sentinel] is returned.
///
- /// The return value can be one of [InstanceRef], [ErrorRef] or [Sentinel].
- Future<dynamic> evaluateInFrame(
+ /// The return value can be one of [InstanceRef] or [ErrorRef].
+ ///
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Response> evaluateInFrame(
String isolateId,
int frameIndex,
String expression, {
@@ -479,8 +492,10 @@
/// If `isolateId` refers to an isolate which has exited, then the `Collected`
/// [Sentinel] is returned.
///
- /// The return value can be one of [AllocationProfile] or [Sentinel].
- Future<dynamic> getAllocationProfile(String isolateId, {bool reset, bool gc});
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<AllocationProfile> getAllocationProfile(String isolateId,
+ {bool reset, bool gc});
/// The `getClientName` RPC is used to retrieve the name associated with the
/// currently connected VM service client. If no name was previously set
@@ -500,8 +515,9 @@
///
/// See [CpuSamples].
///
- /// The return value can be one of [CpuSamples] or [Sentinel].
- Future<dynamic> getCpuSamples(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<CpuSamples> getCpuSamples(
String isolateId, int timeOriginMicros, int timeExtentMicros);
/// The `getFlagList` RPC returns a list of all command line flags in the VM
@@ -535,8 +551,9 @@
///
/// See [InboundReferences].
///
- /// The return value can be one of [InboundReferences] or [Sentinel].
- Future<dynamic> getInboundReferences(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<InboundReferences> getInboundReferences(
String isolateId, String targetId, int limit);
/// The `getInstances` RPC is used to retrieve a set of instances which are of
@@ -561,8 +578,10 @@
///
/// See [InstanceSet].
///
- /// The return value can be one of [InstanceSet] or [Sentinel].
- Future<dynamic> getInstances(String isolateId, String objectId, int limit);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<InstanceSet> getInstances(
+ String isolateId, String objectId, int limit);
/// The `getIsolate` RPC is used to lookup an `Isolate` object by its `id`.
///
@@ -571,8 +590,9 @@
///
/// See [Isolate].
///
- /// The return value can be one of [Isolate] or [Sentinel].
- Future<dynamic> getIsolate(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Isolate> getIsolate(String isolateId);
/// The `getIsolateGroup` RPC is used to lookup an `IsolateGroup` object by
/// its `id`.
@@ -586,8 +606,9 @@
///
/// See [IsolateGroup], [VM].
///
- /// The return value can be one of [IsolateGroup] or [Sentinel].
- Future<dynamic> getIsolateGroup(String isolateGroupId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<IsolateGroup> getIsolateGroup(String isolateGroupId);
/// The `getMemoryUsage` RPC is used to lookup an isolate's memory usage
/// statistics by its `id`.
@@ -597,8 +618,9 @@
///
/// See [Isolate].
///
- /// The return value can be one of [MemoryUsage] or [Sentinel].
- Future<dynamic> getMemoryUsage(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<MemoryUsage> getMemoryUsage(String isolateId);
/// The `getIsolateGroupMemoryUsage` RPC is used to lookup an isolate group's
/// memory usage statistics by its `id`.
@@ -608,8 +630,9 @@
///
/// See [IsolateGroup].
///
- /// The return value can be one of [MemoryUsage] or [Sentinel].
- Future<dynamic> getIsolateGroupMemoryUsage(String isolateGroupId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<MemoryUsage> getIsolateGroupMemoryUsage(String isolateGroupId);
/// The `getScripts` RPC is used to retrieve a `ScriptList` containing all
/// scripts for an isolate based on the isolate's `isolateId`.
@@ -619,8 +642,9 @@
///
/// See [ScriptList].
///
- /// The return value can be one of [ScriptList] or [Sentinel].
- Future<dynamic> getScripts(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<ScriptList> getScripts(String isolateId);
/// The `getObject` RPC is used to lookup an `object` from some isolate by its
/// `id`.
@@ -646,8 +670,9 @@
/// Int32List, Int64List, Flooat32List, Float64List, Inst32x3List,
/// Float32x4List, and Float64x2List. These parameters are otherwise ignored.
///
- /// The return value can be one of [Obj] or [Sentinel].
- Future<dynamic> getObject(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Obj> getObject(
String isolateId,
String objectId, {
int offset,
@@ -676,8 +701,9 @@
///
/// See [RetainingPath].
///
- /// The return value can be one of [RetainingPath] or [Sentinel].
- Future<dynamic> getRetainingPath(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<RetainingPath> getRetainingPath(
String isolateId, String targetId, int limit);
/// The `getStack` RPC is used to retrieve the current execution stack and
@@ -688,8 +714,9 @@
///
/// See [Stack].
///
- /// The return value can be one of [Stack] or [Sentinel].
- Future<dynamic> getStack(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Stack> getStack(String isolateId);
/// The `getSourceReport` RPC is used to generate a set of reports tied to
/// source locations in an isolate.
@@ -728,8 +755,9 @@
///
/// See [SourceReport].
///
- /// The return value can be one of [SourceReport] or [Sentinel].
- Future<dynamic> getSourceReport(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<SourceReport> getSourceReport(
String isolateId,
/*List<SourceReportKind>*/
List<String> reports, {
@@ -799,8 +827,9 @@
///
/// See [Success].
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> pause(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> pause(String isolateId);
/// The `kill` RPC is used to kill an isolate as if by dart:isolate's
/// `Isolate.kill(IMMEDIATE)`.
@@ -812,8 +841,9 @@
///
/// See [Success].
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> kill(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> kill(String isolateId);
/// Registers a service that can be invoked by other VM service clients, where
/// `service` is the name of the service to advertise and `alias` is an
@@ -843,8 +873,9 @@
/// If `isolateId` refers to an isolate which has exited, then the `Collected`
/// [Sentinel] is returned.
///
- /// The return value can be one of [ReloadReport] or [Sentinel].
- Future<dynamic> reloadSources(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<ReloadReport> reloadSources(
String isolateId, {
bool force,
bool pause,
@@ -861,8 +892,9 @@
///
/// See [Success].
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> removeBreakpoint(String isolateId, String breakpointId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> removeBreakpoint(String isolateId, String breakpointId);
/// Requests a dump of the Dart heap of the given isolate.
///
@@ -875,8 +907,9 @@
/// If `isolateId` refers to an isolate which has exited, then the `Collected`
/// [Sentinel] is returned.
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> requestHeapSnapshot(String isolateId);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> requestHeapSnapshot(String isolateId);
/// The `requirePermissionToResume` RPC is used to change the pause/resume
/// behavior of isolates by providing a way for the VM service to wait for
@@ -930,8 +963,9 @@
///
/// See [Success], [StepOption].
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> resume(String isolateId,
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> resume(String isolateId,
{/*StepOption*/ String step, int frameIndex});
/// The `setClientName` RPC is used to set a name to be associated with the
@@ -955,8 +989,9 @@
/// If `isolateId` refers to an isolate which has exited, then the `Collected`
/// [Sentinel] is returned.
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> setExceptionPauseMode(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> setExceptionPauseMode(
String isolateId, /*ExceptionPauseMode*/ String mode);
/// The `setFlag` RPC is used to set a VM flag at runtime. Returns an error if
@@ -966,7 +1001,7 @@
/// The following flags may be set at runtime:
///
/// The return value can be one of [Success] or [Error].
- Future<dynamic> setFlag(String name, String value);
+ Future<Response> setFlag(String name, String value);
/// The `setLibraryDebuggable` RPC is used to enable or disable whether
/// breakpoints and stepping work for a given library.
@@ -976,8 +1011,9 @@
///
/// See [Success].
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> setLibraryDebuggable(
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> setLibraryDebuggable(
String isolateId, String libraryId, bool isDebuggable);
/// The `setName` RPC is used to change the debugging name for an isolate.
@@ -987,8 +1023,9 @@
///
/// See [Success].
///
- /// The return value can be one of [Success] or [Sentinel].
- Future<dynamic> setName(String isolateId, String name);
+ /// This method will throw a [SentinelException] in the case a [Sentinel] is
+ /// returned.
+ Future<Success> setName(String isolateId, String name);
/// The `setVMName` RPC is used to change the debugging name for the vm.
///
@@ -1540,7 +1577,7 @@
Stream<Event> get onStderrEvent => _getEventController('Stderr').stream;
@override
- Future<dynamic> addBreakpoint(
+ Future<Breakpoint> addBreakpoint(
String isolateId,
String scriptId,
int line, {
@@ -1554,7 +1591,7 @@
});
@override
- Future<dynamic> addBreakpointWithScriptUri(
+ Future<Breakpoint> addBreakpointWithScriptUri(
String isolateId,
String scriptUri,
int line, {
@@ -1581,7 +1618,7 @@
Future<Success> clearVMTimeline() => _call('clearVMTimeline');
@override
- Future<dynamic> invoke(
+ Future<Response> invoke(
String isolateId,
String targetId,
String selector,
@@ -1598,7 +1635,7 @@
});
@override
- Future<dynamic> evaluate(
+ Future<Response> evaluate(
String isolateId,
String targetId,
String expression, {
@@ -1615,7 +1652,7 @@
});
@override
- Future<dynamic> evaluateInFrame(
+ Future<Response> evaluateInFrame(
String isolateId,
int frameIndex,
String expression, {
@@ -1656,7 +1693,7 @@
Future<FlagList> getFlagList() => _call('getFlagList');
@override
- Future<dynamic> getInboundReferences(
+ Future<InboundReferences> getInboundReferences(
String isolateId, String targetId, int limit) =>
_call('getInboundReferences',
{'isolateId': isolateId, 'targetId': targetId, 'limit': limit});
@@ -1668,19 +1705,19 @@
{'isolateId': isolateId, 'objectId': objectId, 'limit': limit});
@override
- Future<dynamic> getIsolate(String isolateId) =>
+ Future<Isolate> getIsolate(String isolateId) =>
_call('getIsolate', {'isolateId': isolateId});
@override
- Future<dynamic> getIsolateGroup(String isolateGroupId) =>
+ Future<IsolateGroup> getIsolateGroup(String isolateGroupId) =>
_call('getIsolateGroup', {'isolateGroupId': isolateGroupId});
@override
- Future<dynamic> getMemoryUsage(String isolateId) =>
+ Future<MemoryUsage> getMemoryUsage(String isolateId) =>
_call('getMemoryUsage', {'isolateId': isolateId});
@override
- Future<dynamic> getIsolateGroupMemoryUsage(String isolateGroupId) =>
+ Future<MemoryUsage> getIsolateGroupMemoryUsage(String isolateGroupId) =>
_call('getIsolateGroupMemoryUsage', {'isolateGroupId': isolateGroupId});
@override
@@ -1688,7 +1725,7 @@
_call('getScripts', {'isolateId': isolateId});
@override
- Future<dynamic> getObject(
+ Future<Obj> getObject(
String isolateId,
String objectId, {
int offset,
@@ -1712,7 +1749,7 @@
_call('getStack', {'isolateId': isolateId});
@override
- Future<dynamic> getSourceReport(
+ Future<SourceReport> getSourceReport(
String isolateId,
/*List<SourceReportKind>*/
List<String> reports, {
@@ -1763,7 +1800,7 @@
_call('registerService', {'service': service, 'alias': alias});
@override
- Future<dynamic> reloadSources(
+ Future<ReloadReport> reloadSources(
String isolateId, {
bool force,
bool pause,
@@ -1815,7 +1852,7 @@
_call('setExceptionPauseMode', {'isolateId': isolateId, 'mode': mode});
@override
- Future<dynamic> setFlag(String name, String value) =>
+ Future<Response> setFlag(String name, String value) =>
_call('setFlag', {'name': name, 'value': value});
@override
@@ -1984,7 +2021,9 @@
} else {
Map<String, dynamic> result = json['result'] as Map<String, dynamic>;
String type = result['type'];
- if (_typeFactories[type] == null) {
+ if (type == 'Sentinel') {
+ completer.completeError(SentinelException.parse(methodName, result));
+ } else if (_typeFactories[type] == null) {
completer.complete(Response.parse(result));
} else {
completer.complete(createServiceObject(result, returnTypes));
@@ -2037,7 +2076,7 @@
typedef DisposeHandler = Future Function();
-class RPCError {
+class RPCError implements Exception {
static RPCError parse(String callingMethod, dynamic json) {
return RPCError(callingMethod, json['code'], json['message'], json['data']);
}
@@ -2060,6 +2099,17 @@
}
}
+/// Thrown when an RPC response is a [Sentinel].
+class SentinelException implements Exception {
+ final String callingMethod;
+ final Sentinel sentinel;
+
+ SentinelException.parse(this.callingMethod, Map<String, dynamic> data)
+ : sentinel = Sentinel.parse(data);
+
+ String toString() => '$sentinel from ${callingMethod}()';
+}
+
/// An `ExtensionData` is an arbitrary map that can have any contents.
class ExtensionData {
static ExtensionData parse(Map json) =>
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 99a3026..366bd74 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 3.0.0+1
+version: 4.0.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/async_generator_breakpoint_test.dart b/pkg/vm_service/test/async_generator_breakpoint_test.dart
index 4d52ce4..3cf2655 100644
--- a/pkg/vm_service/test/async_generator_breakpoint_test.dart
+++ b/pkg/vm_service/test/async_generator_breakpoint_test.dart
@@ -48,7 +48,7 @@
Future testAsync(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
- final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
final script = lib.scripts[0];
final bp1 = await service.addBreakpoint(isolate.id, script.id, 11);
@@ -77,10 +77,10 @@
// ignore: unawaited_futures
service
.evaluate(isolate.id, lib.id, 'testerReady = true')
- .then((result) async {
- result = await service.getObject(isolate.id, result.id);
- print(result);
- expect((result as Instance).valueAsString, equals('true'));
+ .then((Response result) async {
+ Obj res = await service.getObject(isolate.id, (result as InstanceRef).id);
+ print(res);
+ expect((res as Instance).valueAsString, equals('true'));
});
final stream = service.onDebugEvent;
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
index e5dea67..55edf13 100644
--- a/pkg/vm_service/test/common/service_test_common.dart
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -117,7 +117,7 @@
return (VmService service, IsolateRef isolateRef) async {
print("Setting breakpoint for line $line");
final isolate = await service.getIsolate(isolateRef.id);
- final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
final script = lib.scripts.first;
Breakpoint bpt = await service.addBreakpoint(isolate.id, script.id, line);
@@ -139,7 +139,8 @@
expect(frames.length, greaterThanOrEqualTo(1));
final top = frames[0];
- final script = await service.getObject(isolate.id, top.location.script.id);
+ final Script script =
+ await service.getObject(isolate.id, top.location.script.id);
int actualLine = script.getLineNumberFromTokenPos(top.location.tokenPos);
if (actualLine != line) {
print("Actual: $actualLine Line: $line");
diff --git a/pkg/vm_service/test/coverage_leaf_function_test.dart b/pkg/vm_service/test/coverage_leaf_function_test.dart
index fe28924..eac959f 100644
--- a/pkg/vm_service/test/coverage_leaf_function_test.dart
+++ b/pkg/vm_service/test/coverage_leaf_function_test.dart
@@ -37,9 +37,11 @@
expect(stack.frames.length, greaterThanOrEqualTo(1));
expect(stack.frames[0].function.name, 'testFunction');
- final root = await service.getObject(isolate.id, isolate.rootLib.id);
- var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
- func = await service.getObject(isolate.id, func.id);
+ final Library root =
+ await service.getObject(isolate.id, isolate.rootLib.id);
+ FuncRef funcRef =
+ root.functions.singleWhere((f) => f.name == 'leafFunction');
+ Func func = await service.getObject(isolate.id, funcRef.id) as Func;
final expectedRange = {
'scriptIndex': 0,
@@ -73,9 +75,11 @@
expect(stack.frames.length, greaterThanOrEqualTo(1));
expect(stack.frames[0].function.name, 'testFunction');
- final root = await service.getObject(isolate.id, isolate.rootLib.id);
- var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
- func = await service.getObject(isolate.id, func.id);
+ final Library root =
+ await service.getObject(isolate.id, isolate.rootLib.id);
+ FuncRef funcRef =
+ root.functions.singleWhere((f) => f.name == 'leafFunction');
+ Func func = await service.getObject(isolate.id, funcRef.id) as Func;
var expectedRange = {
'scriptIndex': 0,
diff --git a/pkg/vm_service/test/debugging_test.dart b/pkg/vm_service/test/debugging_test.dart
index 8bfefd6..df3a1ed 100644
--- a/pkg/vm_service/test/debugging_test.dart
+++ b/pkg/vm_service/test/debugging_test.dart
@@ -80,16 +80,14 @@
}
});
await service.streamListen(EventStreams.kDebug);
- final script =
+ final Script script =
await service.getObject(isolate.id, rootLib.scripts.first.id);
// Add the breakpoint.
- final Breakpoint result =
+ final Breakpoint bpt =
await service.addBreakpoint(isolate.id, script.id, 16);
- print(result);
- expect(result is Breakpoint, isTrue);
- Breakpoint bpt = result;
- expect(bpt.location.script.id, script.id);
- expect(script.getLineNumberFromTokenPos(bpt.location.tokenPos), 16);
+ final SourceLocation location = bpt.location;
+ expect(location.script.id, script.id);
+ expect(script.getLineNumberFromTokenPos(location.tokenPos), 16);
isolate = await service.getIsolate(isolate.id);
expect(isolate.breakpoints.length, 1);
diff --git a/pkg/vm_service/test/eval_test.dart b/pkg/vm_service/test/eval_test.dart
index b751001..4eb8bb5 100644
--- a/pkg/vm_service/test/eval_test.dart
+++ b/pkg/vm_service/test/eval_test.dart
@@ -45,7 +45,7 @@
// Make sure we are in the right place.
expect(stack.frames.length, greaterThanOrEqualTo(2));
expect(stack.frames[0].function.name, 'method');
- expect(stack.frames[0].function.owner.name, 'MyClass');
+ expect((stack.frames[0].function.owner as ClassRef).name, 'MyClass');
final LibraryRef lib = isolate.rootLib;
final ClassRef cls = stack.frames[0].function.owner;
@@ -81,11 +81,12 @@
// Make sure we are in the right place.
expect(stack.frames.length, greaterThanOrEqualTo(2));
expect(stack.frames[0].function.name, 'foo');
- expect(stack.frames[0].function.owner.name, '_MyClass');
+ expect((stack.frames[0].function.owner as ClassRef).name, '_MyClass');
final ClassRef cls = stack.frames[0].function.owner;
- final result = await service.evaluate(isolate.id, cls.id, "1+1");
+ final InstanceRef result =
+ await service.evaluate(isolate.id, cls.id, "1+1");
print(result);
expect(result.valueAsString, "2");
}
diff --git a/pkg/vm_service/test/evaluate_with_scope_test.dart b/pkg/vm_service/test/evaluate_with_scope_test.dart
index ad4a106..38588d8 100644
--- a/pkg/vm_service/test/evaluate_with_scope_test.dart
+++ b/pkg/vm_service/test/evaluate_with_scope_test.dart
@@ -22,13 +22,13 @@
final tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
- final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
- final field1 = await service.getObject(
+ final Field field1 = await service.getObject(
isolate.id, lib.variables.singleWhere((v) => v.name == 'thing1').id);
final thing1 = (await service.getObject(isolate.id, field1.staticValue.id));
- final field2 = await service.getObject(
+ final Field field2 = await service.getObject(
isolate.id, lib.variables.singleWhere((v) => v.name == 'thing2').id);
final thing2 = (await service.getObject(isolate.id, field2.staticValue.id));
diff --git a/pkg/vm_service/test/get_flag_list_rpc_test.dart b/pkg/vm_service/test/get_flag_list_rpc_test.dart
index f7a8b70..8b6c337 100644
--- a/pkg/vm_service/test/get_flag_list_rpc_test.dart
+++ b/pkg/vm_service/test/get_flag_list_rpc_test.dart
@@ -22,16 +22,14 @@
var tests = <VMTest>[
// Modify a flag which does not exist.
(VmService service) async {
- final result = await service.setFlag('does_not_exist', 'true');
- expect(result, TypeMatcher<Error>());
+ final Error result = await service.setFlag('does_not_exist', 'true');
expect(result.message, 'Cannot set flag: flag not found');
},
// Modify a flag with the wrong value type.
(VmService service) async {
- final result =
+ final Error result =
await service.setFlag('pause_isolates_on_start', 'not-boolean');
- expect(result, TypeMatcher<Error>());
expect(result.message, equals('Cannot set flag: invalid value'));
},
@@ -43,8 +41,7 @@
// Modify a flag which cannot be set at runtime.
(VmService service) async {
- final result = await service.setFlag('random_seed', '42');
- expect(result, TypeMatcher<Error>());
+ final Error result = await service.setFlag('random_seed', '42');
expect(result.message, 'Cannot set flag: cannot change at runtime');
},
diff --git a/pkg/vm_service/test/invoke_test.dart b/pkg/vm_service/test/invoke_test.dart
index dcbb16e..651e39e 100644
--- a/pkg/vm_service/test/invoke_test.dart
+++ b/pkg/vm_service/test/invoke_test.dart
@@ -31,7 +31,7 @@
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
- final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
final cls = lib.classes.singleWhere((cls) => cls.name == "Klass");
FieldRef fieldRef =
lib.variables.singleWhere((field) => field.name == "instance");
diff --git a/pkg/vm_service/test/throws_sentinel_test.dart b/pkg/vm_service/test/throws_sentinel_test.dart
new file mode 100644
index 0000000..b399f06
--- /dev/null
+++ b/pkg/vm_service/test/throws_sentinel_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+
+var tests = <VMTest>[
+ (VmService vm) async {
+ try {
+ final res = await vm.getIsolate('isolates/12321');
+ fail('Expected SentinelException, got $res');
+ } on SentinelException catch (e) {
+ // Expected.
+ } catch (e) {
+ fail('Expected SentinelException, got $e');
+ }
+ },
+];
+
+main([args = const <String>[]]) async => await runVMTests(args, tests);
diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart
index 0f62ac2..eb2e6e8 100644
--- a/pkg/vm_service/tool/dart/generate_dart.dart
+++ b/pkg/vm_service/tool/dart/generate_dart.dart
@@ -210,7 +210,9 @@
} else {
Map<String, dynamic> result = json['result'] as Map<String, dynamic>;
String type = result['type'];
- if (_typeFactories[type] == null) {
+ if (type == 'Sentinel') {
+ completer.completeError(SentinelException.parse(methodName, result));
+ } else if (_typeFactories[type] == null) {
completer.complete(Response.parse(result));
} else {
completer.complete(createServiceObject(result, returnTypes));
@@ -265,7 +267,7 @@
typedef DisposeHandler = Future Function();
-class RPCError {
+class RPCError implements Exception {
static RPCError parse(String callingMethod, dynamic json) {
return RPCError(callingMethod, json['code'], json['message'], json['data']);
}
@@ -288,6 +290,17 @@
}
}
+/// Thrown when an RPC response is a [Sentinel].
+class SentinelException implements Exception {
+ final String callingMethod;
+ final Sentinel sentinel;
+
+ SentinelException.parse(this.callingMethod, Map<String, dynamic> data) :
+ sentinel = Sentinel.parse(data);
+
+ String toString() => '$sentinel from ${callingMethod}()';
+}
+
/// An `ExtensionData` is an arbitrary map that can have any contents.
class ExtensionData {
static ExtensionData parse(Map json) =>
@@ -1110,6 +1123,11 @@
'${joinLast(returnType.types.map((t) => '[${t}]'), ', ', ' or ')}.';
_docs = _docs.trim();
}
+ if (returnType.canReturnSentinel) {
+ _docs +=
+ '\n\nThis method will throw a [SentinelException] in the case a [Sentinel] is returned.';
+ _docs = _docs.trim();
+ }
if (_docs.isNotEmpty) gen.writeDocs(_docs);
}
if (withOverrides) gen.writeln('@override');
@@ -1147,10 +1165,11 @@
MemberType();
- void parse(Parser parser) {
+ void parse(Parser parser, {bool isReturnType = false}) {
// foo|bar[]|baz
// (@Instance|Sentinel)[]
bool loop = true;
+ this.isReturnType = isReturnType;
while (loop) {
if (parser.consume('(')) {
@@ -1172,7 +1191,11 @@
parser.expect(']');
ref.arrayDepth++;
}
- types.add(ref);
+ if (isReturnType && ref.name == 'Sentinel') {
+ canReturnSentinel = true;
+ } else {
+ types.add(ref);
+ }
}
loop = parser.consume('|');
@@ -1182,9 +1205,13 @@
String get name {
if (types.isEmpty) return '';
if (types.length == 1) return types.first.ref;
+ if (isReturnType) return 'Response';
return 'dynamic';
}
+ bool isReturnType = false;
+ bool canReturnSentinel = false;
+
bool get isMultipleReturns => types.length > 1;
bool get isSimple => types.length == 1 && types.first.isSimple;
@@ -1923,7 +1950,7 @@
// method is return type, name, (, args )
// args is type name, [optional], comma
- method.returnType.parse(this);
+ method.returnType.parse(this, isReturnType: true);
Token t = expectName();
validate(