Version 2.15.0-292.0.dev

Merge commit '490e625ce78b49c6b57fe405261234623fc4e8f5' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 981de4b..4281850 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -710,6 +710,11 @@
       "languageVersion": "2.12"
     },
     {
+      "name": "test_package",
+      "rootUri": "../pkg/vm_service/test/test_package",
+      "languageVersion": "2.12"
+    },
+    {
       "name": "test_process",
       "rootUri": "../third_party/pkg/test_process",
       "packageUri": "lib/",
diff --git a/.packages b/.packages
index 568fa66..f5ea5bc 100644
--- a/.packages
+++ b/.packages
@@ -105,6 +105,7 @@
 test_api:third_party/pkg/test/pkgs/test_api/lib
 test_core:third_party/pkg/test/pkgs/test_core/lib
 test_descriptor:third_party/pkg/test_descriptor/lib
+test_package:pkg/vm_service/test/test_package
 test_process:third_party/pkg/test_process/lib
 test_reflective_loader:third_party/pkg/test_reflective_loader/lib
 test_runner:pkg/test_runner/lib
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef0ba40..81152a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,10 +2,9 @@
 
 ### Language
 
-The following new features are new in the Dart 2.15 [language version][]. To use
+The following features are new in the Dart 2.15 [language version][]. To use
 them, you must set the lower bound on the SDK constraint for your package to
-2.15 or greater. (If using a beta preview release, use an SDK constraint of
-`>=2.15.0-0`):
+2.15 or greater (`sdk: '>=2.15.0 <3.0.0'`).
 
 [language version]: https://dart.dev/guides/language/evolution
 
@@ -113,12 +112,6 @@
   }
   ```
 
-  Generic type literals are only available as part of the 2.15 [language
-  version](https://dart.dev/guides/language/evolution). To use this feature, you
-  must set the lower bound on the SDK constraint for your package to 2.15 or
-  greater (if using a beta preview release, an SDK constraint of
-  `>=2.15.0-0` must be used).
-
 - **[Explicit generic method instantiations][explicit instantiation]**: Previous
   Dart versions allowed generic methods to be implicitly specialized (or
   "instantiated") to non-generic versions when assigned to a location with a
diff --git a/DEPS b/DEPS
index 5709b47..df4cc35 100644
--- a/DEPS
+++ b/DEPS
@@ -91,7 +91,7 @@
   "collection_rev": "a4c941ab94044d118b2086a3f261c30377604127",
   "convert_rev": "e063fdca4bebffecbb5e6aa5525995120982d9ce",
   "crypto_rev": "b5024e4de2b1c474dd558bef593ddbf0bfade152",
-  "csslib_rev": "6f35da3d93eb56eb25925779d235858d4090ce6f",
+  "csslib_rev": "02abc1ddf93092efef2be365300f15504d23cd23",
 
   # Note: Updates to dart_style have to be coordinated with the infrastructure
   # team so that the internal formatter `tools/sdks/dart-sdk/bin/dart format`
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 2b98916..bbe634a 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -32,8 +32,8 @@
 import 'package:analysis_server/src/plugin/notification_manager.dart';
 import 'package:analysis_server/src/protocol_server.dart' as server;
 import 'package:analysis_server/src/search/search_domain.dart';
-import 'package:analysis_server/src/server/completion_request_aborting.dart';
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
+import 'package:analysis_server/src/server/debounce_requests.dart';
 import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
 import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/server/error_notifier.dart';
@@ -56,6 +56,7 @@
 import 'package:analyzer_plugin/src/utilities/navigation/navigation.dart';
 import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
 import 'package:http/http.dart' as http;
+import 'package:meta/meta.dart';
 import 'package:telemetry/crash_reporting.dart';
 import 'package:telemetry/telemetry.dart' as telemetry;
 import 'package:watcher/watcher.dart';
@@ -116,8 +117,11 @@
 
   final DetachableFileSystemManager? detachableFileSystemManager;
 
-  final CompletionRequestAborting completionRequestAborting =
-      CompletionRequestAborting();
+  /// The broadcast stream of requests that were discarded because there
+  /// was another request that made this one irrelevant.
+  @visibleForTesting
+  final StreamController<Request> discardedRequests =
+      StreamController.broadcast(sync: true);
 
   /// Initialize a newly created server to receive requests from and send
   /// responses to the given [channel].
@@ -171,7 +175,8 @@
         io.pid,
       ).toNotification(),
     );
-    channel.requests.listen(handleRequest, onDone: done, onError: error);
+    debounceRequests(channel, discardedRequests)
+        .listen(handleRequest, onDone: done, onError: error);
     handlers = <server.RequestHandler>[
       ServerDomainHandler(this),
       AnalysisDomainHandler(this),
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index ec4c4f3..1595e38 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -417,7 +417,6 @@
       }
     }
 
-    server.completionRequestAborting.abort();
     server.updateContent(request.id, params.files);
     //
     // Forward the request to the plugins.
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 925a100..76a3f3b 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -297,14 +297,6 @@
       return;
     }
 
-    server.completionRequestAborting.abort();
-    if (await server.completionRequestAborting.waitIfAborted(request)) {
-      return server.sendResponse(
-        CompletionGetSuggestions2Result(offset, 0, [], [], true)
-            .toResponse(request.id),
-      );
-    }
-
     var performance = OperationPerformanceImpl('<root>');
     performance.runAsync(
       'request',
diff --git a/pkg/analysis_server/lib/src/server/completion_request_aborting.dart b/pkg/analysis_server/lib/src/server/completion_request_aborting.dart
deleted file mode 100644
index 8f03f53..0000000
--- a/pkg/analysis_server/lib/src/server/completion_request_aborting.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2021, 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:analysis_server/protocol/protocol.dart';
-import 'package:meta/meta.dart';
-
-class CompletionRequestAborting {
-  /// IDs of requests to abort on another completion request.
-  final Set<String> _pendingRequests = {};
-
-  /// IDs from [_pendingRequests] that we decided to abort.
-  final Set<String> _abortedRequests = {};
-
-  /// The function to be invoked when requests are aborted.
-  @visibleForTesting
-  void Function(Set<String> id)? onAbort;
-
-  /// Abort requests that were pending.
-  void abort() {
-    onAbort?.call(_pendingRequests);
-    _abortedRequests.addAll(_pendingRequests);
-  }
-
-  /// Return `true` if the [request] should be aborted because there is
-  /// another request in the queue, so [abort] was invoked while pumping the
-  /// event queue.
-  Future<bool> waitIfAborted(Request request) async {
-    // Mark the current request as pending.
-    var id = request.id;
-    _pendingRequests.add(id);
-
-    // Wait for more requests to arrive and abort this one.
-    await _pumpEventQueue(64);
-
-    // We are done waiting.
-    _pendingRequests.remove(id);
-
-    // See it the request was aborted.
-    return _abortedRequests.remove(id);
-  }
-
-  static Future<void> _pumpEventQueue(int times) {
-    if (times == 0) return Future.value();
-    return Future(() => _pumpEventQueue(times - 1));
-  }
-}
diff --git a/pkg/analysis_server/lib/src/server/debounce_requests.dart b/pkg/analysis_server/lib/src/server/debounce_requests.dart
new file mode 100644
index 0000000..4ee01d6
--- /dev/null
+++ b/pkg/analysis_server/lib/src/server/debounce_requests.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2021, 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 'dart:async';
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_constants.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/channel/channel.dart';
+
+/// Return the stream of requests that is filtered to exclude requests for
+/// which the client does not need actual responses.
+///
+/// If there is one completion request, and then another completion request,
+/// then most probably the user continued typing, and there is no need to
+/// compute results for the first request. But we will have to respond, an
+/// empty response is enough.
+///
+/// Discarded requests are reported into [discardedRequests].
+Stream<Request> debounceRequests(
+  ServerCommunicationChannel channel,
+  StreamController<Request> discardedRequests,
+) {
+  return _DebounceRequests(channel, discardedRequests).requests;
+}
+
+class _DebounceRequests {
+  final ServerCommunicationChannel channel;
+  final StreamController<Request> discardedRequests;
+  late final Stream<Request> requests;
+
+  _DebounceRequests(this.channel, this.discardedRequests) {
+    var buffer = <Request>[];
+    Timer? timer;
+
+    requests = channel.requests.transform(
+      StreamTransformer.fromHandlers(
+        handleData: (request, sink) {
+          buffer.add(request);
+          // Accumulate requests for a short period of time.
+          // When we were busy processing a request, the client could put
+          // multiple requests into the event queue. So, when we look, we will
+          // quickly get all of them. So, even 1 ms should be enough.
+          timer ??= Timer(const Duration(milliseconds: 1), () {
+            timer = null;
+            var filtered = _filterCompletion(buffer);
+            buffer = [];
+            for (var request in filtered) {
+              sink.add(request);
+            }
+          });
+        },
+      ),
+    );
+  }
+
+  List<Request> _filterCompletion(List<Request> requests) {
+    var reversed = <Request>[];
+    var abortCompletionRequests = false;
+    for (var request in requests.reversed) {
+      if (request.method == ANALYSIS_REQUEST_UPDATE_CONTENT) {
+        abortCompletionRequests = true;
+      }
+      if (request.method == COMPLETION_REQUEST_GET_SUGGESTIONS2) {
+        if (abortCompletionRequests) {
+          discardedRequests.add(request);
+          var params = CompletionGetSuggestions2Params.fromRequest(request);
+          var offset = params.offset;
+          channel.sendResponse(
+            CompletionGetSuggestions2Result(offset, 0, [], [], true)
+                .toResponse(request.id),
+          );
+          continue;
+        } else {
+          abortCompletionRequests = true;
+        }
+      }
+      reversed.add(request);
+    }
+    return reversed.reversed.toList();
+  }
+}
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 226a8b8..d4f174f 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -230,9 +230,9 @@
 
   Future<void> test_abort_onAnotherCompletionRequest() async {
     var abortedIdSet = <String>{};
-    server.completionRequestAborting.onAbort = (idSet) {
-      abortedIdSet.addAll(idSet);
-    };
+    server.discardedRequests.stream.listen((request) {
+      abortedIdSet.add(request.id);
+    });
 
     newFile(testFilePath, content: '');
 
@@ -268,9 +268,9 @@
 
   Future<void> test_abort_onUpdateContent() async {
     var abortedIdSet = <String>{};
-    server.completionRequestAborting.onAbort = (idSet) {
-      abortedIdSet.addAll(idSet);
-    };
+    server.discardedRequests.stream.listen((request) {
+      abortedIdSet.add(request.id);
+    });
 
     newFile(testFilePath, content: '');
 
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 81e92a4..2984592 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -21,3 +21,5 @@
   process: ^4.0.0
   pub_semver: ^2.0.0-nullsafety.0
   test: ^1.16.0-nullsafety.13
+  test_package:
+    path: 'test/test_package'
diff --git a/pkg/vm_service/test/add_breakpoint_rpc_kernel_test.dart b/pkg/vm_service/test/add_breakpoint_rpc_kernel_test.dart
new file mode 100644
index 0000000..bead75c
--- /dev/null
+++ b/pkg/vm_service/test/add_breakpoint_rpc_kernel_test.dart
@@ -0,0 +1,178 @@
+// Copyright (c) 2017, 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 'dart:async';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 24;
+const int LINE_B = 26;
+
+int value = 0;
+
+int incValue(int amount) {
+  value += amount;
+  return amount;
+}
+
+Future testMain() async {
+  incValue(incValue(1)); // line A.
+
+  incValue(incValue(1)); // line B.
+}
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+
+  // Test future breakpoints.
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLib =
+        await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
+    final rootLibId = rootLib.id!;
+    final scriptId = rootLib.scripts![0].id!;
+    final script = await service.getObject(isolateId, scriptId) as Script;
+
+    // Future breakpoint.
+    var futureBpt1 = await service.addBreakpoint(isolateId, scriptId, LINE_A);
+    expect(futureBpt1.breakpointNumber, 1);
+    expect(futureBpt1.resolved, isFalse);
+    expect(await futureBpt1.location!.line!, LINE_A);
+    expect(await futureBpt1.location!.column, null);
+
+    // Future breakpoint with specific column.
+    var futureBpt2 =
+        await service.addBreakpoint(isolateId, scriptId, LINE_A, column: 3);
+    expect(futureBpt2.breakpointNumber, 2);
+    expect(futureBpt2.resolved, isFalse);
+    expect(await futureBpt2.location!.line!, LINE_A);
+    expect(await futureBpt2.location!.column!, 3);
+
+    int resolvedCount = await resumeAndCountResolvedBreakpointsUntilPause(
+      service,
+      isolate,
+    );
+
+    // After resolution the breakpoints have assigned line & column.
+    expect(resolvedCount, 2);
+
+    // Refresh objects
+    futureBpt1 =
+        await service.getObject(isolateId, futureBpt1.id!) as Breakpoint;
+    futureBpt2 =
+        await service.getObject(isolateId, futureBpt2.id!) as Breakpoint;
+
+    expect(futureBpt1.resolved, isTrue);
+    expect(script.getLineNumberFromTokenPos(futureBpt1.location!.tokenPos!),
+        LINE_A);
+    expect(
+        script.getColumnNumberFromTokenPos(futureBpt1.location!.tokenPos!), 12);
+    expect(futureBpt2.resolved, isTrue);
+    expect(script.getLineNumberFromTokenPos(futureBpt2.location!.tokenPos!),
+        LINE_A);
+    expect(
+        script.getColumnNumberFromTokenPos(futureBpt2.location!.tokenPos!), 3);
+
+    // The first breakpoint hits before value is modified.
+    InstanceRef result =
+        await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
+    expect(result.valueAsString, '0');
+
+    await service.resume(isolateId);
+    await hasStoppedAtBreakpoint(service, isolate);
+
+    // The second breakpoint hits after value has been modified once.
+    result =
+        await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
+    expect(result.valueAsString, '1');
+
+    // Remove the breakpoints.
+    expect((await service.removeBreakpoint(isolateId, futureBpt1.id!)).type,
+        'Success');
+    expect((await service.removeBreakpoint(isolateId, futureBpt2.id!)).type,
+        'Success');
+  },
+
+  // Test resolution of column breakpoints.
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLibId = isolate.rootLib!.id!;
+    final rootLib = await service.getObject(isolateId, rootLibId) as Library;
+
+    final scriptId = rootLib.scripts![0].id!;
+    final script = await service.getObject(isolateId, scriptId) as Script;
+
+    // Try all columns, including some columns that are too big.
+    for (int col = 1; col <= 50; col++) {
+      final bpt =
+          await service.addBreakpoint(isolateId, scriptId, LINE_A, column: col);
+      expect(bpt.resolved, isTrue);
+      int resolvedLine =
+          script.getLineNumberFromTokenPos(bpt.location!.tokenPos!)!;
+      int resolvedCol =
+          script.getColumnNumberFromTokenPos(bpt.location!.tokenPos!)!;
+      print('$LINE_A:${col} -> ${resolvedLine}:${resolvedCol}');
+      if (col <= 12) {
+        expect(resolvedLine, LINE_A);
+        expect(resolvedCol, 3);
+      } else if (col <= 36) {
+        expect(resolvedLine, LINE_A);
+        expect(resolvedCol, 12);
+      } else {
+        expect(resolvedLine, LINE_B);
+        expect(resolvedCol, 12);
+      }
+      expect(
+          (await service.removeBreakpoint(isolateId, bpt.id!)).type, 'Success');
+    }
+
+    // Make sure that a zero column is an error.
+    var caughtException = false;
+    try {
+      await service.addBreakpoint(isolateId, scriptId, 20, column: 0);
+      expect(false, isTrue, reason: 'Unreachable');
+    } on RPCError catch (e) {
+      caughtException = true;
+      expect(e.code, RPCError.kInvalidParams);
+      expect(e.details, "addBreakpoint: invalid 'column' parameter: 0");
+    }
+    expect(caughtException, isTrue);
+  },
+];
+
+Future<int> resumeAndCountResolvedBreakpointsUntilPause(
+    VmService service, Isolate isolate) async {
+  final completer = Completer<void>();
+  late StreamSubscription subscription;
+  int resolvedCount = 0;
+
+  subscription = service.onDebugEvent.listen((event) {
+    if (event.kind == EventKind.kBreakpointResolved) {
+      resolvedCount++;
+    } else if (event.kind == EventKind.kPauseBreakpoint) {
+      subscription.cancel();
+      service.streamCancel(EventStreams.kDebug);
+      completer.complete();
+    }
+  });
+  await service.streamListen(EventStreams.kDebug);
+
+  await service.resume(isolate.id!);
+  await completer.future;
+  return resolvedCount;
+}
+
+main(args) => runIsolateTests(
+      args,
+      tests,
+      'add_breakpoint_rpc_kernel_test.dart',
+      testeeConcurrent: testMain,
+      pause_on_start: true,
+    );
diff --git a/pkg/vm_service/test/allocations_test.dart b/pkg/vm_service/test/allocations_test.dart
new file mode 100644
index 0000000..9e38e57
--- /dev/null
+++ b/pkg/vm_service/test/allocations_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2014, 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:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/test_helper.dart';
+
+class Foo {}
+
+// Prevent TFA from removing this static field to ensure the objects are kept
+// alive, so the allocation stats will report them via the service api.
+@pragma('vm:entry-point')
+List<Foo>? foos;
+
+void script() {
+  foos = [
+    Foo(),
+    Foo(),
+    Foo(),
+  ];
+}
+
+var tests = <IsolateTest>[
+  (VmService service, IsolateRef isolateRef) async {
+    var profile = await service.callMethod('_getAllocationProfile',
+        isolateId: isolateRef.id!) as AllocationProfile;
+    print(profile.runtimeType);
+    var classHeapStats = profile.members!.singleWhere((stats) {
+      return stats.classRef!.name == 'Foo';
+    });
+    expect(classHeapStats.instancesCurrent, 3);
+    expect(classHeapStats.instancesAccumulated, 3);
+  },
+];
+
+main(args) => runIsolateTests(
+      args,
+      tests,
+      'allocations_test.dart',
+      testeeBefore: script,
+    );
diff --git a/pkg/vm_service/test/async_next_regression_18877_test.dart b/pkg/vm_service/test/async_next_regression_18877_test.dart
new file mode 100644
index 0000000..6912a67
--- /dev/null
+++ b/pkg/vm_service/test/async_next_regression_18877_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2018, 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.
+// VMOptions=--verbose_debug
+
+import 'dart:developer';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 24;
+const int LINE_B = 25;
+const int LINE_C = 26;
+
+foo() async {}
+
+doAsync(stop) async {
+  // Flutter issue 18877:
+  // If a closure is defined in the context of an async method, stepping over
+  // an await causes the implicit breakpoint to be set for that closure instead
+  // of the async_op, resulting in the debugger falling through.
+  final baz = () => print('doAsync($stop) done!');
+  if (stop) debugger();
+  await foo(); // Line A.
+  await foo(); // Line B.
+  await foo(); // Line C.
+  baz();
+  return null;
+}
+
+testMain() {
+  // With two runs of doAsync floating around, async step should only cause
+  // us to stop in the run we started in.
+  doAsync(false);
+  doAsync(true);
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  stepOver, // foo()
+  stoppedAtLine(LINE_A),
+  asyncNext,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  stepOver, // foo()
+  stoppedAtLine(LINE_B),
+  asyncNext,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  resumeIsolate,
+];
+
+main(args) => runIsolateTests(
+      args,
+      tests,
+      'async_next_regression_18877_test.dart',
+      testeeConcurrent: testMain,
+    );
diff --git a/pkg/vm_service/test/awaiter_async_stack_contents_2_test.dart b/pkg/vm_service/test/awaiter_async_stack_contents_2_test.dart
new file mode 100644
index 0000000..88d17d0a
--- /dev/null
+++ b/pkg/vm_service/test/awaiter_async_stack_contents_2_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2018, 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.
+//
+// VMOptions=--async-debugger --verbose-debug --lazy-async-stacks
+
+import 'dart:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 28;
+const LINE_B = 34;
+const LINE_C = 38;
+
+notCalled() async {
+  await null;
+  await null;
+  await null;
+  await null;
+}
+
+foobar() async {
+  await null;
+  debugger();
+  print('foobar'); // LINE_A.
+}
+
+helper() async {
+  await null;
+  print('helper');
+  await foobar(); // LINE_B.
+}
+
+testMain() async {
+  helper(); // LINE_C.
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolate) async {
+    final isolateId = isolate.id!;
+    // Verify awaiter stack trace is the current frame + the awaiter.
+    Stack stack = await service.getStack(isolateId);
+    expect(stack.awaiterFrames, isNotNull);
+    List<Frame> awaiterFrames = stack.awaiterFrames!;
+    expect(awaiterFrames.length, greaterThanOrEqualTo(2));
+    // Awaiter frame.
+    expect(awaiterFrames[0].function!.owner.name, 'foobar');
+    // Awaiter frame.
+    expect(awaiterFrames[1].function!.owner.name, 'helper');
+  },
+];
+
+main(args) => runIsolateTestsSynchronous(
+      args,
+      tests,
+      'awaiter_async_stack_contents_2_test.dart',
+      testeeConcurrent: testMain,
+      extraArgs: extraDebuggingArgs,
+    );
diff --git a/pkg/vm_service/test/awaiter_async_stack_contents_test.dart b/pkg/vm_service/test/awaiter_async_stack_contents_test.dart
new file mode 100644
index 0000000..0fea350
--- /dev/null
+++ b/pkg/vm_service/test/awaiter_async_stack_contents_test.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2017, 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.
+//
+// VMOptions=--async-debugger --verbose-debug --lazy-async-stacks
+
+import 'dart:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_C = 22;
+const LINE_A = 28;
+const LINE_B = 34;
+const LINE_D = 29;
+
+foobar() async {
+  await null;
+  debugger();
+  print('foobar'); // LINE_C.
+}
+
+helper() async {
+  await null;
+  debugger();
+  print('helper'); // LINE_A.
+  await foobar(); // LINE_D
+}
+
+testMain() {
+  debugger();
+  helper(); // LINE_B.
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  (VmService service, IsolateRef isolateRef) async {
+    Stack stack = await service.getStack(isolateRef.id!);
+    // No awaiter frames because we are in a completely synchronous stack.
+    expect(stack.awaiterFrames, isNull);
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  (VmService service, IsolateRef isolateRef) async {
+    // Verify awaiter stack trace is the current frame + the awaiter.
+    Stack stack = await service.getStack(isolateRef.id!);
+    expect(stack.awaiterFrames, isNotNull);
+    List<Frame> awaiterFrames = stack.awaiterFrames!;
+
+    expect(awaiterFrames.length, greaterThanOrEqualTo(2));
+    // Awaiter frame.
+    expect(await awaiterFrames[0].function!.owner.name, 'foobar');
+    // Awaiter frame.
+    expect(await awaiterFrames[1].function!.owner.name, 'helper');
+    // "helper" is not await'ed.
+  },
+];
+
+main(args) => runIsolateTestsSynchronous(
+      args,
+      tests,
+      'awaiter_async_stack_contents_test.dart',
+      testeeConcurrent: testMain,
+      extraArgs: extraDebuggingArgs,
+    );
diff --git a/pkg/vm_service/test/breakpoint_async_break_test.dart b/pkg/vm_service/test/breakpoint_async_break_test.dart
new file mode 100644
index 0000000..d0c2443
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_async_break_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2019, 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 'dart:async';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 18;
+
+// Issue: https://github.com/dart-lang/sdk/issues/36622
+Future<void> testMain() async {
+  for (int i = 0; i < 2; i++) {
+    if (i > 0) {
+      break; // breakpoint here
+    }
+    await Future.delayed(Duration(seconds: 1));
+  }
+}
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  // Test future breakpoints.
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLib =
+        await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
+    final scriptId = rootLib.scripts![0].id!;
+    final script = await service.getObject(isolateId, scriptId) as Script;
+
+    // Future breakpoint.
+    var futureBpt = await service.addBreakpoint(isolateId, scriptId, LINE);
+    expect(futureBpt.breakpointNumber, 1);
+    expect(futureBpt.resolved, isFalse);
+    expect(await futureBpt.location!.line, LINE);
+    expect(await futureBpt.location!.column, null);
+
+    final completer = Completer<void>();
+    int resolvedCount = 0;
+    late StreamSubscription subscription;
+    subscription = service.onDebugEvent.listen((event) {
+      if (event.kind == EventKind.kBreakpointResolved) {
+        resolvedCount++;
+      } else if (event.kind == EventKind.kPauseBreakpoint) {
+        subscription.cancel();
+        service.streamCancel(EventStreams.kDebug);
+        completer.complete();
+      }
+    });
+
+    await service.streamListen(EventStreams.kDebug);
+    await service.resume(isolateId);
+    await hasStoppedAtBreakpoint(service, isolate);
+
+    // After resolution the breakpoints have assigned line & column.
+    expect(resolvedCount, 1);
+    futureBpt = await service.getObject(isolateId, futureBpt.id!) as Breakpoint;
+    expect(futureBpt.resolved, isTrue);
+    expect(
+        script.getLineNumberFromTokenPos(futureBpt.location!.tokenPos), LINE);
+    expect(script.getColumnNumberFromTokenPos(futureBpt.location!.tokenPos), 7);
+
+    // Remove the breakpoints.
+    expect((await service.removeBreakpoint(isolateId, futureBpt.id!)).type,
+        'Success');
+  },
+];
+
+main(args) => runIsolateTests(
+      args,
+      tests,
+      'breakpoint_async_break_test.dart',
+      testeeConcurrent: testMain,
+      pause_on_start: true,
+    );
diff --git a/pkg/vm_service/test/breakpoint_in_package_parts_class_file_uri_test.dart b/pkg/vm_service/test/breakpoint_in_package_parts_class_file_uri_test.dart
new file mode 100644
index 0000000..70cd0fd
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_package_parts_class_file_uri_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2019, 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 'dart:io' show Platform;
+
+import 'package:path/path.dart' as path;
+import 'package:test_package/has_part.dart' as has_part;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+// Chop off the file name.
+String baseDirectory = path.dirname(Platform.script.path) + '/';
+Uri baseUri = Platform.script.replace(path: baseDirectory);
+Uri breakpointFile = baseUri.resolve('test_package/the_part.dart');
+const String shortFile = "the_part.dart";
+
+const int LINE = 87;
+
+code() {
+  has_part.main();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$shortFile:${LINE + 0}:5", // on 'print'
+  "$shortFile:${LINE + 1}:3" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(breakpointFile.toString(), LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main([args = const <String>[]]) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_in_package_parts_class_file_uri_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_in_package_parts_class_test.dart b/pkg/vm_service/test/breakpoint_in_package_parts_class_test.dart
new file mode 100644
index 0000000..2dcf30f
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_package_parts_class_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, 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.
+
+library breakpoint_in_parts_class;
+
+import 'package:test_package/has_part.dart' as has_part;
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 87;
+const String breakpointFile = "package:test_package/the_part.dart";
+const String shortFile = "the_part.dart";
+
+code() {
+  has_part.main();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$shortFile:${LINE + 0}:5", // on 'print'
+  "$shortFile:${LINE + 1}:3" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(breakpointFile, LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_in_package_parts_class_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_in_parts_class_part.dart b/pkg/vm_service/test/breakpoint_in_parts_class_part.dart
new file mode 100644
index 0000000..4855332
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_parts_class_part.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2017, 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.
+
+part of breakpoint_in_parts_class;
+
+void foo() {
+  print("lalala");
+}
+
+class Foo1 {
+  final foo;
+
+  Foo1(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo2 {
+  final foo;
+
+  Foo2(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo3 {
+  final foo;
+
+  Foo3(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo4 {
+  final foo;
+
+  Foo4(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo5 {
+  final foo;
+
+  Foo5(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo6 {
+  final foo;
+
+  Foo6(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo7 {
+  final foo;
+
+  Foo7(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo8 {
+  final foo;
+
+  Foo8(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo9 {
+  final foo;
+
+  Foo9(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo10 {
+  final foo;
+
+  Foo10(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+var foo2 = foo() as dynamic;
diff --git a/pkg/vm_service/test/breakpoint_in_parts_class_test.dart b/pkg/vm_service/test/breakpoint_in_parts_class_test.dart
new file mode 100644
index 0000000..89f4e7f
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_in_parts_class_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2017, 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.
+
+library breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+part 'breakpoint_in_parts_class_part.dart';
+
+const int LINE = 87;
+const String file = "breakpoint_in_parts_class_part.dart";
+
+code() {
+  final foo = Foo10("Foo!");
+  print(foo);
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$file:${LINE + 0}:5", // on 'print'
+  "$file:${LINE + 1}:3" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(file, LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_in_parts_class_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_non_debuggable_library_test.dart b/pkg/vm_service/test/breakpoint_non_debuggable_library_test.dart
new file mode 100644
index 0000000..4ecd5c4
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_non_debuggable_library_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2019, 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:test/test.dart';
+import 'package:test_package/has_part.dart' as test_pkg;
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const String file = 'package:test_package/has_part.dart';
+// print() within fooz()
+const int LINE_A = 15;
+// print() within barz()
+const int LINE_B = 11;
+
+testMain() {
+  test_pkg.fooz();
+}
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  (VmService service, IsolateRef isolateRef) async {
+    // Mark 'package:observatory_test_package/has_part.dart' as not debuggable.
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+
+    LibraryRef has_part_ref = isolate.libraries!.firstWhere(
+      (LibraryRef library) => library.uri == file,
+    );
+
+    Library has_part =
+        await service.getObject(isolateId, has_part_ref.id!) as Library;
+    expect(has_part.debuggable, true);
+    // SetBreakpoint before setting library to non-debuggable.
+    // Breakpoints are allowed to be set (before marking library as
+    // non-debuggable) but are not hit when running (after marking library
+    // as non-debuggable).
+    ScriptRef script = has_part.scripts!.firstWhere(
+      (ScriptRef script) => script.uri == file,
+    );
+    Breakpoint bpt = await service.addBreakpoint(isolateId, script.id!, LINE_A);
+    print("Breakpoint is $bpt");
+    expect(bpt, isNotNull);
+
+    // Set breakpoint and check later that this breakpoint won't be added if
+    // the library is non-debuggable.
+    bpt = await service.addBreakpoint(isolateId, script.id!, LINE_B);
+    print("Breakpoint is $bpt");
+    expect(bpt, isNotNull);
+
+    // Remove breakpoint.
+    final res = await service.removeBreakpoint(isolateId, bpt.id!);
+    expect(res.type, 'Success');
+
+    await service.setLibraryDebuggable(isolateId, has_part.id!, false);
+    has_part = await service.getObject(isolateId, has_part.id!) as Library;
+    expect(has_part.debuggable, false);
+    print('$has_part is debuggable: ${has_part.debuggable}');
+
+    // Breakpoints are not allowed to set on non-debuggable libraries.
+    try {
+      await service.addBreakpoint(isolateId, script.id!, LINE_B);
+    } on RPCError catch (e) {
+      // Cannot add breakpoint error code
+      expect(e.code, 102);
+      expect(e.details, contains("Cannot add breakpoint at line '11'"));
+      print("Set Breakpoint to non-debuggable library is not allowed");
+    }
+  },
+  resumeIsolate,
+  hasStoppedAtExit,
+];
+
+main(args) => runIsolateTests(
+      args,
+      tests,
+      'breakpoint_non_debuggable_library_test.dart',
+      testeeConcurrent: testMain,
+      pause_on_start: true,
+      pause_on_exit: true,
+    );
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_1_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_1_test.dart
new file mode 100644
index 0000000..c46cabe
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_1_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2019, 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.
+
+library breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 18;
+const String file = "breakpoint_on_if_null_1_test.dart";
+
+code() {
+  foo(42);
+}
+
+foo(dynamic args) {
+  if (args == null) {
+    print("was null");
+  }
+  if (args != null) {
+    print("was not null");
+  }
+  if (args == 42) {
+    print("was 42!");
+  }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$file:${LINE + 0}:12", // on '=='
+  "$file:${LINE + 3}:12", // on '!='
+  "$file:${LINE + 4}:5", // on 'print'
+  "$file:${LINE + 6}:12", // on '=='
+  "$file:${LINE + 7}:5", // on 'print'
+  "$file:${LINE + 9}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(file, LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_on_if_null_1_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_2_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_2_test.dart
new file mode 100644
index 0000000..69bee59
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_2_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2019, 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.
+
+library breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 21;
+const String file = "breakpoint_on_if_null_2_test.dart";
+
+dynamic compareWithMe = 43;
+
+code() {
+  compareWithMe = null;
+  foo(42);
+}
+
+foo(dynamic args) {
+  if (args == compareWithMe) {
+    print("was null");
+  }
+  if (args != compareWithMe) {
+    print("was not null");
+  }
+  if (args == 42) {
+    print("was 42!");
+  }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$file:${LINE + 0}:12", // on '=='
+  "$file:${LINE + 3}:12", // on '!='
+  "$file:${LINE + 4}:5", // on 'print'
+  "$file:${LINE + 6}:12", // on '=='
+  "$file:${LINE + 7}:5", // on 'print'
+  "$file:${LINE + 9}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(file, LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_on_if_null_2_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_3_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_3_test.dart
new file mode 100644
index 0000000..9211410
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_3_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, 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.
+
+library breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 17;
+const String file = "breakpoint_on_if_null_3_test.dart";
+
+code() {
+  foo(42);
+}
+
+foo(dynamic args) {
+  if (args == null) {
+    print("was null");
+  }
+  if (args != null) {
+    print("was not null");
+  }
+  if (args == 42) {
+    print("was 42!");
+  }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$file:${LINE + 0}:13", // on 'args'
+  "$file:${LINE + 1}:12", // on '=='
+  "$file:${LINE + 4}:12", // on '!='
+  "$file:${LINE + 5}:5", // on 'print'
+  "$file:${LINE + 7}:12", // on '=='
+  "$file:${LINE + 8}:5", // on 'print'
+  "$file:${LINE + 10}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(file, LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_on_if_null_3_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_on_if_null_4_test.dart b/pkg/vm_service/test/breakpoint_on_if_null_4_test.dart
new file mode 100644
index 0000000..08b7760
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_on_if_null_4_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2019, 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.
+
+library breakpoint_in_parts_class;
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 20;
+const String file = "breakpoint_on_if_null_4_test.dart";
+
+dynamic compareWithMe = 43;
+
+code() {
+  compareWithMe = null;
+  foo(42);
+}
+
+foo(dynamic args) {
+  if (args == compareWithMe) {
+    print("was null");
+  }
+  if (args != compareWithMe) {
+    print("was not null");
+  }
+  if (args == 42) {
+    print("was 42!");
+  }
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$file:${LINE + 0}:13", // on 'args'
+  "$file:${LINE + 1}:12", // on '=='
+  "$file:${LINE + 4}:12", // on '!='
+  "$file:${LINE + 5}:5", // on 'print'
+  "$file:${LINE + 7}:12", // on '=='
+  "$file:${LINE + 8}:5", // on 'print'
+  "$file:${LINE + 10}:1", // on ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(file, LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_on_if_null_4_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_partfile_test.dart b/pkg/vm_service/test/breakpoint_partfile_test.dart
new file mode 100644
index 0000000..a3c5fd1
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_partfile_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, 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.
+
+library breakpoint_in_parts_class;
+
+import 'package:test_package/has_part.dart' as has_part;
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE = 8;
+const String breakpointFile = "package:test_package/the_part_2.dart";
+const String shortFile = "the_part_2.dart";
+
+code() {
+  has_part.bar();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$shortFile:${LINE + 0}:3", // on 'print'
+  "$shortFile:${LINE + 1}:1" // on class ending '}'
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(breakpointFile, LINE),
+  runStepThroughProgramRecordingStops(stops),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoint_partfile_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/breakpoint_two_args_checked_test.dart b/pkg/vm_service/test/breakpoint_two_args_checked_test.dart
new file mode 100644
index 0000000..40d0dc6
--- /dev/null
+++ b/pkg/vm_service/test/breakpoint_two_args_checked_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2016, 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.
+// VMOptions=--verbose_debug
+
+// TODO(bkonyi): consider deleting now that DBC is no more.
+// This test was mostly interesting for DBC, which needed to patch two bytecodes
+// to create a breakpoint for fast Smi ops.
+
+import 'dart:developer';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 29;
+const int LINE_B = 30;
+const int LINE_C = 31;
+
+class NotGeneric {}
+
+testeeMain() {
+  final x = List<dynamic>.filled(1, null);
+  final y = 7;
+  debugger();
+  print("Statement");
+  x[0] = 3; // Line A.
+  x is NotGeneric; // Line B.
+  y & 4; // Line C.
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+
+// Add breakpoints.
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    Library rootLib =
+        await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
+
+    final script =
+        await service.getObject(isolateId, rootLib.scripts![0].id!) as Script;
+    final scriptId = script.id!;
+
+    final bpt1 = await service.addBreakpoint(isolateId, scriptId, LINE_A);
+    print(bpt1);
+    expect(bpt1.resolved, isTrue);
+    expect(script.getLineNumberFromTokenPos(bpt1.location!.tokenPos),
+        equals(LINE_A));
+
+    final bpt2 = await service.addBreakpoint(isolateId, scriptId, LINE_B);
+    print(bpt2);
+    expect(bpt2.resolved, isTrue);
+    expect(script.getLineNumberFromTokenPos(bpt2.location!.tokenPos),
+        equals(LINE_B));
+
+    final bpt3 = await service.addBreakpoint(isolateId, scriptId, LINE_C);
+    print(bpt3);
+    expect(bpt3.resolved, isTrue);
+    expect(script.getLineNumberFromTokenPos(bpt3.location!.tokenPos),
+        equals(LINE_C));
+  },
+
+  resumeIsolate,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  resumeIsolate,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  resumeIsolate,
+
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  resumeIsolate,
+];
+
+main(args) => runIsolateTests(
+      args,
+      tests,
+      'breakpoint_two_args_checked_test.dart',
+      testeeConcurrent: testeeMain,
+    );
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_lib1.dart b/pkg/vm_service/test/breakpoints_with_mixin_lib1.dart
new file mode 100644
index 0000000..3c43715
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_lib1.dart
@@ -0,0 +1,7 @@
+// 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 "breakpoints_with_mixin_lib3.dart";
+
+class Test1 extends Object with Foo {}
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_lib2.dart b/pkg/vm_service/test/breakpoints_with_mixin_lib2.dart
new file mode 100644
index 0000000..c054176
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_lib2.dart
@@ -0,0 +1,7 @@
+// 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 "breakpoints_with_mixin_lib3.dart";
+
+class Test2 extends Object with Foo {}
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_lib3.dart b/pkg/vm_service/test/breakpoints_with_mixin_lib3.dart
new file mode 100644
index 0000000..a7329de
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_lib3.dart
@@ -0,0 +1,15 @@
+// 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.
+
+class Foo {
+  foo() {
+    print("I should be breakable!");
+  }
+}
+
+class Bar {
+  bar() {
+    print("I should be breakable too!");
+  }
+}
diff --git a/pkg/vm_service/test/breakpoints_with_mixin_test.dart b/pkg/vm_service/test/breakpoints_with_mixin_test.dart
new file mode 100644
index 0000000..f382628
--- /dev/null
+++ b/pkg/vm_service/test/breakpoints_with_mixin_test.dart
@@ -0,0 +1,62 @@
+// 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 "breakpoints_with_mixin_lib1.dart";
+import "breakpoints_with_mixin_lib2.dart";
+import "breakpoints_with_mixin_lib3.dart";
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const String testFilename = "breakpoints_with_mixin_test.dart";
+const int testCodeLineStart = 17;
+const String lib3Filename = "breakpoints_with_mixin_lib3.dart";
+const int lib3Bp1 = 7;
+const int lib3Bp2 = 13;
+
+void code() {
+  Test1 test1 = Test1();
+  test1.foo();
+  Test2 test2 = Test2();
+  test2.foo();
+  Foo foo = Foo();
+  foo.foo();
+  Bar bar = Bar();
+  bar.bar();
+  test1.foo();
+  test2.foo();
+  foo.foo();
+  bar.bar();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 2}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 4}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 6}:7)",
+  "$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 8}:7)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 9}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 10}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 11}:7)",
+  "$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 12}:7)",
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(lib3Filename, lib3Bp1),
+  setBreakpointAtUriAndLine(lib3Filename, lib3Bp2),
+  resumeProgramRecordingStops(stops, true),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(
+    args,
+    tests,
+    'breakpoints_with_mixin_test.dart',
+    testeeConcurrent: code,
+    pause_on_start: true,
+    pause_on_exit: true,
+  );
+}
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
index 4f616ab..6e84d16 100644
--- a/pkg/vm_service/test/common/service_test_common.dart
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -6,6 +6,7 @@
 
 import 'dart:async';
 
+import 'package:path/path.dart';
 import 'package:test/test.dart';
 import 'package:vm_service/vm_service.dart';
 
@@ -131,6 +132,16 @@
   };
 }
 
+IsolateTest setBreakpointAtUriAndLine(String uri, int line) {
+  return (VmService service, IsolateRef isolateRef) async {
+    print("Setting breakpoint for line $line in $uri");
+    Breakpoint bpt =
+        await service.addBreakpointWithScriptUri(isolateRef.id!, uri, line);
+    print("Breakpoint is $bpt");
+    expect(bpt, isNotNull);
+  };
+}
+
 IsolateTest stoppedAtLine(int line) {
   return (VmService service, IsolateRef isolateRef) async {
     print("Checking we are at line $line");
@@ -221,3 +232,154 @@
   await hasStoppedAtBreakpoint(service, isolateRef);
   await _unsubscribeDebugStream(service);
 }
+
+IsolateTest resumeProgramRecordingStops(
+    List<String> recordStops, bool includeCaller) {
+  return (VmService service, IsolateRef isolateRef) async {
+    final completer = Completer<void>();
+
+    late StreamSubscription subscription;
+    subscription = service.onDebugEvent.listen((event) async {
+      if (event.kind == EventKind.kPauseBreakpoint) {
+        final stack = await service.getStack(isolateRef.id!);
+        final frames = stack.frames!;
+        expect(frames.length, greaterThanOrEqualTo(2));
+
+        String brokeAt =
+            await _locationToString(service, isolateRef, frames[0]);
+        if (includeCaller) {
+          brokeAt =
+              '$brokeAt (${await _locationToString(service, isolateRef, frames[1])})';
+        }
+        recordStops.add(brokeAt);
+        await service.resume(isolateRef.id!);
+      } else if (event.kind == EventKind.kPauseExit) {
+        await subscription.cancel();
+        await service.streamCancel(EventStreams.kDebug);
+        completer.complete();
+      }
+    });
+
+    await service.streamListen(EventStreams.kDebug);
+    await service.resume(isolateRef.id!);
+    return completer.future;
+  };
+}
+
+Future<String> _locationToString(
+  VmService service,
+  IsolateRef isolateRef,
+  Frame frame,
+) async {
+  final location = frame.location!;
+  Script script =
+      await service.getObject(isolateRef.id!, location.script!.id!) as Script;
+  final scriptName = basename(script.uri!);
+  final tokenPos = location.tokenPos!;
+  final line = script.getLineNumberFromTokenPos(tokenPos);
+  final column = script.getColumnNumberFromTokenPos(tokenPos);
+  return '$scriptName:$line:$column';
+}
+
+IsolateTest runStepThroughProgramRecordingStops(List<String> recordStops) {
+  return (VmService service, IsolateRef isolateRef) async {
+    final completer = Completer<void>();
+
+    late StreamSubscription subscription;
+    subscription = service.onDebugEvent.listen((event) async {
+      if (event.kind == EventKind.kPauseBreakpoint) {
+        final isolate = await service.getIsolate(isolateRef.id!);
+        final frame = isolate.pauseEvent!.topFrame!;
+        recordStops.add(await _locationToString(service, isolateRef, frame));
+        if (event.atAsyncSuspension ?? false) {
+          await service.resume(isolateRef.id!,
+              step: StepOption.kOverAsyncSuspension);
+        } else {
+          await service.resume(isolateRef.id!, step: StepOption.kOver);
+        }
+      } else if (event.kind == EventKind.kPauseExit) {
+        await subscription.cancel();
+        await service.streamCancel(EventStreams.kDebug);
+        completer.complete();
+      }
+    });
+
+    await service.streamListen(EventStreams.kDebug);
+    await service.resume(isolateRef.id!);
+    return completer.future;
+  };
+}
+
+IsolateTest checkRecordedStops(
+    List<String> recordStops, List<String> expectedStops,
+    {bool removeDuplicates = false,
+    bool debugPrint = false,
+    String? debugPrintFile,
+    int? debugPrintLine}) {
+  return (VmService service, IsolateRef isolate) async {
+    if (debugPrint) {
+      for (int i = 0; i < recordStops.length; i++) {
+        String line = recordStops[i];
+        String output = line;
+        int firstColon = line.indexOf(":");
+        int lastColon = line.lastIndexOf(":");
+        if (debugPrintFile != null &&
+            debugPrintLine != null &&
+            firstColon > 0 &&
+            lastColon > 0) {
+          int lineNumber = int.parse(line.substring(firstColon + 1, lastColon));
+          int relativeLineNumber = lineNumber - debugPrintLine;
+          var columnNumber = line.substring(lastColon + 1);
+          var file = line.substring(0, firstColon);
+          if (file == debugPrintFile) {
+            output = '\$file:\${LINE+$relativeLineNumber}:$columnNumber';
+          }
+        }
+        String comma = i == recordStops.length - 1 ? "" : ",";
+        print('"$output"$comma');
+      }
+    }
+    if (removeDuplicates) {
+      recordStops = removeAdjacentDuplicates(recordStops);
+      expectedStops = removeAdjacentDuplicates(expectedStops);
+    }
+
+    // Single stepping may record extra stops.
+    // Allow the extra ones as long as the expected ones are recorded.
+    int i = 0;
+    int j = 0;
+    while (i < recordStops.length && j < expectedStops.length) {
+      if (recordStops[i] != expectedStops[j]) {
+        // Check if recordStops[i] is an extra stop.
+        int k = i + 1;
+        while (k < recordStops.length && recordStops[k] != expectedStops[j]) {
+          k++;
+        }
+        if (k < recordStops.length) {
+          // Allow and ignore extra recorded stops from i to k-1.
+          i = k;
+        } else {
+          // This will report an error.
+          expect(recordStops[i], expectedStops[j]);
+        }
+      }
+      i++;
+      j++;
+    }
+
+    expect(recordStops.length >= expectedStops.length, true,
+        reason: "Expects at least ${expectedStops.length} breaks, "
+            "got ${recordStops.length}.");
+  };
+}
+
+List<String> removeAdjacentDuplicates(List<String> fromList) {
+  List<String> result = <String>[];
+  String? latestLine;
+  for (String s in fromList) {
+    if (s == latestLine) continue;
+    latestLine = s;
+    result.add(s);
+  }
+  return result;
+}
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index 45ce97b..585722f 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -277,6 +277,7 @@
         vm = await vmServiceConnectUri(serviceWebsocketAddress);
         print('Done loading VM');
         isolate = await getFirstIsolate(vm);
+        print('Got first isolate');
       });
     });
 
@@ -326,19 +327,24 @@
     Completer<dynamic>? completer = Completer();
     late StreamSubscription subscription;
     subscription = service.onIsolateEvent.listen((Event event) async {
+      print('Isolate event: $event');
       if (completer == null) {
         await subscription.cancel();
         return;
       }
       if (event.kind == EventKind.kIsolateRunnable) {
+        print(event.isolate!.name);
         vm = await service.getVM();
-        assert(vmIsolates.isNotEmpty);
+        //assert(vmIsolates.isNotEmpty);
         await subscription.cancel();
-        completer!.complete(vmIsolates.first);
+        await service.streamCancel(EventStreams.kIsolate);
+        completer!.complete(event.isolate!);
         completer = null;
       }
     });
 
+    await service.streamListen(EventStreams.kIsolate);
+
     // The isolate may have started before we subscribed.
     vm = await service.getVM();
     if (vmIsolates.isNotEmpty) {
diff --git a/pkg/vm_service/test/test_package/has_part.dart b/pkg/vm_service/test/test_package/has_part.dart
new file mode 100644
index 0000000..fb68ee7
--- /dev/null
+++ b/pkg/vm_service/test/test_package/has_part.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, 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.
+
+library has_part;
+
+part 'the_part.dart';
+part 'the_part_2.dart';
+
+barz() {
+  print('in bar!');
+}
+
+fooz() {
+  print('in foo!');
+  bar();
+}
+
+main() {
+  Foo10 foo = Foo10("Foo!");
+  print(foo);
+}
diff --git a/pkg/vm_service/test/test_package/pubspec.yaml b/pkg/vm_service/test/test_package/pubspec.yaml
new file mode 100644
index 0000000..b5bc9d7
--- /dev/null
+++ b/pkg/vm_service/test/test_package/pubspec.yaml
@@ -0,0 +1,4 @@
+name: test_package
+publish_to: none
+environment:
+  sdk: '>=2.12.0-0 <3.0.0'
diff --git a/pkg/vm_service/test/test_package/the_part.dart b/pkg/vm_service/test/test_package/the_part.dart
new file mode 100644
index 0000000..d8545f8
--- /dev/null
+++ b/pkg/vm_service/test/test_package/the_part.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2019, 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.
+
+part of has_part;
+
+void foo() {
+  print("lalala");
+}
+
+class Foo1 {
+  final foo;
+
+  Foo1(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo2 {
+  final foo;
+
+  Foo2(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo3 {
+  final foo;
+
+  Foo3(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo4 {
+  final foo;
+
+  Foo4(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo5 {
+  final foo;
+
+  Foo5(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo6 {
+  final foo;
+
+  Foo6(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo7 {
+  final foo;
+
+  Foo7(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo8 {
+  final foo;
+
+  Foo8(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo9 {
+  final foo;
+
+  Foo9(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+class Foo10 {
+  final foo;
+
+  Foo10(this.foo) {
+    print("hello from foo!");
+  }
+}
+
+var foo2 = foo() as dynamic;
diff --git a/pkg/vm_service/test/test_package/the_part_2.dart b/pkg/vm_service/test/test_package/the_part_2.dart
new file mode 100644
index 0000000..c38df9c
--- /dev/null
+++ b/pkg/vm_service/test/test_package/the_part_2.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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.
+
+part of has_part;
+
+void bar() {
+  print('Should break here');
+}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index e474f19..37f1772 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -222,7 +222,7 @@
     if (Dart_IsError(result)) goto failed;
   } else {
     result = DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri));
-    if (Dart_IsError(result)) return result != nullptr;
+    if (Dart_IsError(result)) goto failed;
 
     if (isolate_group_data->kernel_buffer().get() != nullptr) {
       // Various core-library parts will send requests to the Loader to resolve
diff --git a/tests/standalone/io/directory_rename_test.dart b/tests/standalone/io/directory_rename_test.dart
index 9d31374..0d31c07 100644
--- a/tests/standalone/io/directory_rename_test.dart
+++ b/tests/standalone/io/directory_rename_test.dart
@@ -51,7 +51,8 @@
         // On Windows, the directory will be *deleted*.
         Expect.isFalse(dir.existsSync());
         Expect.isTrue(
-            e.osError!.message.contains('cannot find the file specified'));
+            e.osError!.message.contains('cannot find the file specified'),
+            'Unexpected error: $e');
       } else {
         Expect.fail('Directory.rename to same path should not fail on '
             '${Platform.operatingSystem} (${Platform.operatingSystemVersion}): '
@@ -74,9 +75,11 @@
       Expect.fail('Directory.rename should fail to rename a non-directory');
     } on FileSystemException catch (e) {
       if (Platform.isLinux || Platform.isMacOS) {
-        Expect.isTrue(e.osError!.message.contains('Not a directory'));
+        Expect.isTrue(e.osError!.message.contains('Not a directory'),
+            'Unexpected error: $e');
       } else if (Platform.isWindows) {
-        Expect.isTrue(e.osError!.message.contains('file already exists'));
+        Expect.isTrue(e.osError!.message.contains('file already exists'),
+            'Unexpected error: $e');
       }
     }
   });
@@ -122,7 +125,8 @@
       }
     } on FileSystemException catch (e) {
       if (Platform.isLinux || Platform.isMacOS) {
-        Expect.isTrue(e.osError!.message.contains('Directory not empty'));
+        Expect.isTrue(e.osError!.message.contains('Directory not empty'),
+            'Unexpected error: $e');
       }
     }
   });
diff --git a/tests/standalone/io/platform_test.dart b/tests/standalone/io/platform_test.dart
index dacd0a8..3729439 100644
--- a/tests/standalone/io/platform_test.dart
+++ b/tests/standalone/io/platform_test.dart
@@ -8,6 +8,18 @@
 import "package:async_helper/async_helper.dart";
 import "package:expect/expect.dart";
 
+final executableSuffix = Platform.isWindows ? '.exe' : '';
+final jitExecutableName = 'dart$executableSuffix';
+final aotExecutableName = 'dart_precompiled_runtime$executableSuffix';
+
+bool hasJitOrAotExecutableName(String executable) =>
+    executable.endsWith(jitExecutableName) ||
+    executable.endsWith(aotExecutableName);
+
+bool isRunningFromSource() =>
+    Platform.executable.endsWith(jitExecutableName) &&
+    Platform.script.toFilePath().endsWith('.dart');
+
 test() {
   Expect.isTrue(Platform.numberOfProcessors > 0);
   var os = Platform.operatingSystem;
@@ -23,13 +35,10 @@
   Expect.isTrue(hostname is String && hostname != "");
   var environment = Platform.environment;
   Expect.isTrue(environment is Map<String, String>);
-  if (!Platform.isWindows) {
-    Expect.isTrue(Platform.executable.endsWith('dart'));
-    Expect.isTrue(Platform.resolvedExecutable.endsWith('dart'));
-  } else {
-    Expect.isTrue(Platform.executable.endsWith('dart.exe'));
-    Expect.isTrue(Platform.resolvedExecutable.endsWith('dart.exe'));
-  }
+
+  Expect.isTrue(hasJitOrAotExecutableName(Platform.executable));
+  Expect.isTrue(hasJitOrAotExecutableName(Platform.resolvedExecutable));
+
   if (!Platform.isWindows) {
     Expect.isTrue(Platform.resolvedExecutable.startsWith('/'));
   } else {
@@ -42,9 +51,11 @@
   // Move directory to be sure script is correct.
   var oldDir = Directory.current;
   Directory.current = Directory.current.parent;
-  Expect.isTrue(
-      Platform.script.path.endsWith('tests/standalone/io/platform_test.dart'));
-  Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+  if (isRunningFromSource()) {
+    Expect.isTrue(Platform.script.path
+        .endsWith('tests/standalone/io/platform_test.dart'));
+    Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+  }
 }
 
 void f(reply) {
@@ -58,7 +69,7 @@
 testIsolate() {
   asyncStart();
   ReceivePort port = new ReceivePort();
-  var remote = Isolate.spawn(f, port.sendPort);
+  Isolate.spawn(f, port.sendPort);
   port.first.then((results) {
     Expect.equals(Platform.executable, results["Platform.executable"]);
 
@@ -66,7 +77,10 @@
     // SpawnFunction retains the script url of the parent which in this
     // case was a relative path.
     Expect.equals("file", uri.scheme);
-    Expect.isTrue(uri.path.endsWith('tests/standalone/io/platform_test.dart'));
+    if (isRunningFromSource()) {
+      Expect.isTrue(
+          uri.path.endsWith('tests/standalone/io/platform_test.dart'));
+    }
     Expect.listEquals(
         Platform.executableArguments, results["Platform.executableArguments"]);
     asyncEnd();
diff --git a/tests/standalone/standalone_kernel.status b/tests/standalone/standalone_kernel.status
index a628ff4..a958509 100644
--- a/tests/standalone/standalone_kernel.status
+++ b/tests/standalone/standalone_kernel.status
@@ -91,7 +91,6 @@
 io/http_server_close_response_after_error_test: Skip # Flaky.
 io/http_shutdown_test: Skip # Flaky.
 io/https_client_certificate_test: Crash
-io/platform_test: Crash
 io/raw_datagram_socket_test: Skip # Flaky.
 io/raw_secure_server_closing_test: Skip # Flaky
 io/raw_socket_test: Crash
diff --git a/tests/standalone/standalone_precompiled.status b/tests/standalone/standalone_precompiled.status
index f6c27d2..536731b 100644
--- a/tests/standalone/standalone_precompiled.status
+++ b/tests/standalone/standalone_precompiled.status
@@ -21,7 +21,6 @@
 io/named_pipe_script_test: Skip
 io/namespace_test: Skip # Issue 33168
 io/platform_resolved_executable_test: Skip
-io/platform_test: RuntimeError # Expects to be running from 'dart' instead of 'dart_precompiled_runtime'
 io/print_sync_test: Skip
 io/process_check_arguments_test: Skip
 io/process_detached_test: Skip
diff --git a/tests/standalone_2/io/directory_rename_test.dart b/tests/standalone_2/io/directory_rename_test.dart
index e943a8a..50af674 100644
--- a/tests/standalone_2/io/directory_rename_test.dart
+++ b/tests/standalone_2/io/directory_rename_test.dart
@@ -53,7 +53,8 @@
         // On Windows, the directory will be *deleted*.
         Expect.isFalse(dir.existsSync());
         Expect.isTrue(
-            e.osError.message.contains('cannot find the file specified'));
+            e.osError.message.contains('cannot find the file specified'),
+            'Unexpected error: $e');
       } else {
         Expect.fail('Directory.rename to same path should not fail on '
             '${Platform.operatingSystem} (${Platform.operatingSystemVersion}): '
@@ -76,9 +77,11 @@
       Expect.fail('Directory.rename should fail to rename a non-directory');
     } on FileSystemException catch (e) {
       if (Platform.isLinux || Platform.isMacOS) {
-        Expect.isTrue(e.osError.message.contains('Not a directory'));
+        Expect.isTrue(e.osError.message.contains('Not a directory'),
+            'Unexpected error: $e');
       } else if (Platform.isWindows) {
-        Expect.isTrue(e.osError.message.contains('file already exists'));
+        Expect.isTrue(e.osError.message.contains('file already exists'),
+            'Unexpected error: $e');
       }
     }
   });
@@ -124,7 +127,8 @@
       }
     } on FileSystemException catch (e) {
       if (Platform.isLinux || Platform.isMacOS) {
-        Expect.isTrue(e.osError.message.contains('Directory not empty'));
+        Expect.isTrue(e.osError.message.contains('Directory not empty'),
+            'Unexpected error: $e');
       }
     }
   });
diff --git a/tests/standalone_2/io/platform_test.dart b/tests/standalone_2/io/platform_test.dart
index dfe18ba..e58632d 100644
--- a/tests/standalone_2/io/platform_test.dart
+++ b/tests/standalone_2/io/platform_test.dart
@@ -10,6 +10,18 @@
 import "package:async_helper/async_helper.dart";
 import "package:expect/expect.dart";
 
+final executableSuffix = Platform.isWindows ? '.exe' : '';
+final jitExecutableName = 'dart$executableSuffix';
+final aotExecutableName = 'dart_precompiled_runtime$executableSuffix';
+
+bool hasJitOrAotExecutableName(String executable) =>
+    executable.endsWith(jitExecutableName) ||
+    executable.endsWith(aotExecutableName);
+
+bool isRunningFromSource() =>
+    Platform.executable.endsWith(jitExecutableName) &&
+    Platform.script.toFilePath().endsWith('.dart');
+
 test() {
   Expect.isTrue(Platform.numberOfProcessors > 0);
   var os = Platform.operatingSystem;
@@ -25,13 +37,10 @@
   Expect.isTrue(hostname is String && hostname != "");
   var environment = Platform.environment;
   Expect.isTrue(environment is Map<String, String>);
-  if (!Platform.isWindows) {
-    Expect.isTrue(Platform.executable.endsWith('dart'));
-    Expect.isTrue(Platform.resolvedExecutable.endsWith('dart'));
-  } else {
-    Expect.isTrue(Platform.executable.endsWith('dart.exe'));
-    Expect.isTrue(Platform.resolvedExecutable.endsWith('dart.exe'));
-  }
+
+  Expect.isTrue(hasJitOrAotExecutableName(Platform.executable));
+  Expect.isTrue(hasJitOrAotExecutableName(Platform.resolvedExecutable));
+
   if (!Platform.isWindows) {
     Expect.isTrue(Platform.resolvedExecutable.startsWith('/'));
   } else {
@@ -44,9 +53,11 @@
   // Move directory to be sure script is correct.
   var oldDir = Directory.current;
   Directory.current = Directory.current.parent;
-  Expect.isTrue(Platform.script.path
-      .endsWith('tests/standalone_2/io/platform_test.dart'));
-  Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+  if (isRunningFromSource()) {
+    Expect.isTrue(Platform.script.path
+        .endsWith('tests/standalone_2/io/platform_test.dart'));
+    Expect.isTrue(Platform.script.toFilePath().startsWith(oldDir.path));
+  }
 }
 
 void f(reply) {
@@ -60,7 +71,7 @@
 testIsolate() {
   asyncStart();
   ReceivePort port = new ReceivePort();
-  var remote = Isolate.spawn(f, port.sendPort);
+  Isolate.spawn(f, port.sendPort);
   port.first.then((results) {
     Expect.equals(Platform.executable, results["Platform.executable"]);
 
@@ -68,8 +79,10 @@
     // SpawnFunction retains the script url of the parent which in this
     // case was a relative path.
     Expect.equals("file", uri.scheme);
-    Expect.isTrue(
-        uri.path.endsWith('tests/standalone_2/io/platform_test.dart'));
+    if (isRunningFromSource()) {
+      Expect.isTrue(
+          uri.path.endsWith('tests/standalone_2/io/platform_test.dart'));
+    }
     Expect.listEquals(
         Platform.executableArguments, results["Platform.executableArguments"]);
     asyncEnd();
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index 548f99c..77236ea 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -93,7 +93,6 @@
 io/http_server_close_response_after_error_test: Skip # Flaky.
 io/http_shutdown_test: Skip # Flaky.
 io/https_client_certificate_test: Crash
-io/platform_test: Crash
 io/raw_datagram_socket_test: Skip # Flaky.
 io/raw_secure_server_closing_test: Skip # Flaky
 io/raw_socket_test: Crash
diff --git a/tests/standalone_2/standalone_2_precompiled.status b/tests/standalone_2/standalone_2_precompiled.status
index cf466ae..07c20e7 100644
--- a/tests/standalone_2/standalone_2_precompiled.status
+++ b/tests/standalone_2/standalone_2_precompiled.status
@@ -18,7 +18,6 @@
 io/named_pipe_script_test: Skip
 io/namespace_test: Skip # Issue 33168
 io/platform_resolved_executable_test: Skip
-io/platform_test: RuntimeError # Expects to be running from 'dart' instead of 'dart_precompiled_runtime'
 io/print_sync_test: Skip
 io/process_check_arguments_test: Skip
 io/process_detached_test: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 0754943..87e29e7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 291
+PRERELEASE 292
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/generate_package_config.dart b/tools/generate_package_config.dart
index 066eb2c..d6c7b56 100644
--- a/tools/generate_package_config.dart
+++ b/tools/generate_package_config.dart
@@ -56,6 +56,7 @@
     packageDirectory('runtime/observatory_2'),
     packageDirectory(
         'runtime/observatory_2/tests/service_2/observatory_test_package_2'),
+    packageDirectory('pkg/vm_service/test/test_package'),
     packageDirectory('sdk/lib/_internal/sdk_library_metadata'),
     packageDirectory('third_party/devtools/devtools_server'),
     packageDirectory('third_party/devtools/devtools_shared'),