blob: 316d53611a6be91549f7241537a59c06f1d64645 [file] [log] [blame]
// Copyright (c) 2013, 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 scheduled_server.handler;
import 'dart:async';
import '../../scheduled_server.dart';
import '../../scheduled_test.dart';
import '../utils.dart';
/// A handler for a single request to a [ScheduledServer].
class Handler {
/// The server for which this handler will handle a request.
final ScheduledServer server;
/// The expected method of the request to be handled.
final String method;
/// The expected path of the request to be handled.
final String path;
/// The function to run to handle the request.
ScheduledHandler get fn => _fn;
ScheduledHandler _fn;
/// The scheduled task immediately prior to this handler. If this task is
/// running when this handler receives a request, it should wait until the
/// task has completed.
///
/// The last task in the queue will be the prior task because a Handler is
/// created before its associated [schedule] call.
final Task _taskBefore = currentSchedule.tasks.contents.last;
/// The result of running this handler. If an error occurs while running the
/// handler, that will be piped through this [Future].
Future get result => _resultCompleter.future;
final _resultCompleter = new Completer();
/// Whether it's time for the handler to receive its request.
var ready = false;
Handler(this.server, this.method, this.path, ScheduledHandler fn) {
_fn = (request) {
return _waitForTask().then((_) {
if (!ready) {
fail("'${server.description}' received "
"$method $path earlier than expected.");
}
// Use a nested call to [schedule] to help the user tell the difference
// between a test failing while waiting for a handler and a test failing
// while executing a handler.
chainToCompleter(schedule(() {
return new Future.sync(() {
if (request.method != method || request.uri.path != path) {
fail("'${server.description}' expected $method $path, "
"but got ${request.method} ${request.uri.path}.");
}
return fn(request);
});
}, "'${server.description}' handling ${request.method} ${request.uri}"),
_resultCompleter);
});
};
}
/// If the current task is [_taskBefore], waits for it to finish before
/// completing. Otherwise, completes immediately.
Future _waitForTask() {
return pumpEventQueue().then((_) {
if (currentSchedule.currentTask != _taskBefore) return;
// If we're one task before the handler was scheduled, wait for that
// task to complete and pump the event queue so that [ready] will be
// set.
return _taskBefore.result.then((_) => pumpEventQueue());
});
}
}