Hacking Observatory

These instructions will guide you through the Observatory development and testing workflow.

SDK Setup & Build

Getting ready to start.

Before you start to hack on Observatory, follow the instructions to have a working environment in which you are able to build and test the Dart SDK.

Run existing tests

Before hacking Observatory let's run the existing Observatory tests. We suggest to run all the test in debug mode.

First build the sdk in debug mode

$ ./tools/build.py --mode debug create_sdk

From the root of the sdk repository run:

$ ./tools/test.py -mdebug service

Serve Observatory

Observatory is built as part of building the sdk. Previously, it was recommended to run the Observatory using pub serve to avoid having to rebuild the sdk for each change to Observatory. However, pub serve was deprecated as part of the transition to Dart 2.0.

Issue #35678 tracks changes required to allow for package:build_runner to run Observatory without having to rebuild the sdk after each change.

Connect to a VM

Start a Dart VM with the --observe flag (as explained in the get started guide) and connect your Observatory instance to that VM.

Example script (file name clock.dart):

import 'dart:async' show Timer, Duration;

main() {
  bool tick = true;
  new Timer.periodic(const Duration(seconds: 1), (Timer t) {
    print(tick ? 'tick' : 'tock');
    tick = !tick;
  });
}

Start the script:

$ dart --disable-service-origin-check --observe clock.dart

Code Reviews

The development workflow of Dart (and Observatory) is based on code reviews.

Follow the code review instructions to be able to successfully submit your code.

The main reviewers for Observatory related CLs are:

  • asiva
  • bkonyi
  • rmacnak

Write a new service test

All the service tests are located in the tests/service folder. Test file names follow the convention <description>_test.dart (e.g. a_brief_description_test.dart).

The test is generally structured in the following way.

import 'package:test/test.dart';

main() {
  // Some code that you need to test.
  var a = 1 + 2;

  // Some assertions to check the results.
  expect(a, equal(3));
}

See the official test library instructions;

The test_helper.dart file expose some functions that allow to run a part of the code into another VM.

To test synchronous operations:

import 'test_helper.dart';

code() {
  // Write the code you want to be execute into another VM.
}

var tests = [
  // A series of tests that you want to run against the above code.
  (Isolate isolate) async {
    await isolate.reload();
    // Use the isolate to communicate to the VM.
  }
];

main(args) => runIsolateTestsSynchronous(args,
                                        tests,
                                        testeeConcurrent: code);

In order to test asynchronous operations:

import 'test_helper.dart';

code() async {
  // Write the asynchronous code you want to be execute into another VM.
}

var tests = [
  // A series of tests that you want to run against the above code.
  (Isolate isolate) async {
    await isolate.reload();
    // Use the isolate to communicate to the VM.
  }
];

main(args) async => runIsolateTests(args,
                                    tests,
                                    testeeConcurrent: code);

Both runIsolateTests and runIsolateTestsSynchronous have the following named parameters:

  • testeeBefore (void()) a function that is going to be executed before the test
  • testeeConcurrent (void()) test that is going to be executed
  • pause_on_start (bool, default: false) pause the Isolate before the first instruction
  • pause_on_exit (bool, default: false) pause the Isolate after the last instruction
  • pause_on_unhandled_exceptions (bool, default: false) pause the Isolate at an unhandled exception
  • trace_service (bool, default: false) trace VM service requests
  • trace_compiler (bool, default: false) trace compiler operations
  • verbose_vm (bool, default: false) verbose logging

Some common and reusable test are available from service_test_common.dart:

  • hasPausedFor
    • hasStoppedAtBreakpoint
    • hasStoppedWithUnhandledException
    • hasStoppedAtExit
    • hasPausedAtStartcode_review and utility functions:
  • subscribeToStream
  • cancelStreamSubscription
  • asyncStepOver
  • setBreakpointAtLine
  • resumeIsolate
  • resumeAndAwaitEvent
  • resumeIsolateAndAwaitEvent
  • stepOver
  • getClassFromRootLib
  • rootLibraryFieldValue

Run your tests

See: Run existing tests