text: Probably my favorite feature of the Dart Weekly newsletter is the package update section. Chris Buckett does a nice job of culling a few interesting little packages that I would otherwise overlook. It is fun to see some of the interesting, smaller projects that are going on in Dart-land. And every now and then I come across one that seems like it might be of use.
  In this week's issue, the phrase “runtime scripts integrated with unit tests” caught my eye in the Hop project. I have been running an HTTP server to support some of my Dart tests. Maybe it will be of some help? Heck, even if I can't use it now, it's always fun to try something new. To the Dart cave!
  I start with the usual update of Hipster MVC's
  pubspec.yamlto depend on the Hop package:
  name: hipster_mvc version: 0.2.6 description: Dart-based MVC framework author: Chris Strom <chris@eeecomputes.com> homepage: dependencies: unittest: any dirty: any uuid: any browser: any hop: anyFollowed by a quick
  pub install:
  ➜ hipster-mvc git:(http-test-server) ✗ pub install Resolving dependencies............... Downloading bot 0.22.0 from hosted... Downloading bot_io 0.21.2 from hosted... Downloading hop 0.22.2 from hosted... Dependencies installed!The project wiki has some pretty nice documentation. Per the Setup section, I create
  binsub-directory and copy Hop's
  hopcommand into it:
  ➜ hipster-mvc git:(http-test-server) ✗ mkdir bin ➜ hipster-mvc git:(http-test-server) ✗ cp /home/chris/.pub-cache/hosted/pub.dartlang.org/hop-0.22.2/bin/hop binI wonder if this might be better placed in
  toolas it is an internal script, but I stick with the convention for now.
  Next up, I convert my existing
  test/test_server.dartscript to a library so that it can be imported and called from another script:
  library test_server; // import stuff here.. Future<HttpServer> run() { var port = 31337; return HttpServer.bind('127.0.0.1', port) ..then((app) { app.listen((HttpRequest req) { // process requests like normal }); print('Server started on port: ${port}'); }); }Starting a server is an asynchronous undertaking, so I return the
  Futurefrom the
  HttpServer.bind()call. Hopefully, that is all that I need to do in
  test_server.dart.
  Now, I create
  tool/hop_runner.dartand define my start and stop server tasks:
  import 'package:hop/hop.dart'; import '../test/test_server.dart' as TestServer; import 'dart:async'; void main() { addAsyncTask('test_server:start', _startTestServer); addTask('test_server:stop', _stopTestServer); runHop(); }This should give me two hop tasks:
  test_server:startand
  test_server:stop. But first, I need to define the two associated task functions.
  I am unsure how I will be able to stop the server, so I leave the
  _stopTestServer()function definition blank for now. In
  _startTestServer(), I build a
  startedcompleter that I can use to mark the task completed once the server's future is marked complete:
  Future<bool> _startTestServer(TaskContext content) { var started = new Completer(); TestServer.run().then((_) { started.complete(true); }); return started.future; } bool _stopTestServer(TaskContext context) { // Not sure how this will work... return true; }When I ask Hop for a list of tasks, however, I am greeted with:
  ➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop Unhandled exception: Illegal argument: "name" -- The value "test_server:start" does not contain the pattern "JSRegExp: pattern=^[a-z]([a-z0-9_\-]*[a-z0-9])?$ flags="Bother. I suppose colons are reserved for future nesting support. I prefer
  test_server:startmostly because I am used to that from the Rails world. A dash should suffice for now:
  void main() { addAsyncTask('test_server-start', _startTestServer); addTask('test_server-stop', _stopTestServer); runHop(); }With that, I am ready to try this from the command line:
  ➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-start Unhandled exception: type '(TaskContext) => bool' is not a subtype of type 'Task' of 'task'. #0 addTask (package:hop/hop.dart:54:32) #1 main ()Weird! I had expected that I might get a problem from my async task with actual code, but it is no-op
  addTask()that is causing trouble. It turns out that this should be
  addSyncTask(), not
  addTask(). Both
  addAsyncTask()and
  addSyncTask()convert their callbacks into
  Taskobjects that can be submitted to
  addTask(). I make the change:
  void main() { addAsyncTask('test_server-start', _startTestServer); addSyncTask('test_server-stop', _stopTestServer); runHop(); }And then re-run
  hopto find:
  ➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-start Server started on port: 31337Yay! It worked. Except…
  My server shuts down immediately. As soon as the Hop process exits, the Dart VM containing the server exits as well. In other words, running the server from inside Hop's hop_runner.dart ain't gonna work.
  So instead, I revert all of my changes to my
  test_server.dartso that it needs to be run from the command line as
  dart test/test_server.dart. Then, in Hop's
  hop_runner.dart, I fork a shell process:
  import 'package:hop/hop.dart'; import '../test/test_server.dart' as TestServer; import 'dart:async'; import 'dart:io'; void main() { addAsyncTask('test_server-start', _startTestServer); addSyncTask('test_server-stop', _stopTestServer); runHop(); } Future<bool> _startTestServer(TaskContext content) { var started = new Completer(); Process.start('dart', ['test/test_server.dart'], runInShell: true).then((_) { started.complete(true); }); return started.future; }With that, I am able to start my test web server from the command line:
  ➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-start ➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 783 1 0 23:56 pts/23 00:00:00 /bin/sh -c 'dart' 'test/test_server.dart' chris 784 783 3 23:56 pts/23 00:00:00 dart test/test_server.dart ➜ hipster-mvc git:(http-test-server) ✗ curl {"foo":1}%I am still forced to manually kill the server:
  ➜ hipster-mvc git:(http-test-server) ✗ kill 784But that is something that I ought to be able to improve upon another day.
  For now, it seems that I can make use of
  hopin my test suite. I am unsure if it will prove a significant improvement on what I already have, but it ought to suffice as a suitable framework for building future improvements.
  Day #810