Skip to content

Commit

Permalink
Refactor test servers to make them less global.
Browse files Browse the repository at this point in the history
This sets the stage for adding tests for #1386.

R=rnystrom@google.com

Review URL: https://codereview.chromium.org//1664563002 .
  • Loading branch information
nex3 committed Feb 3, 2016
1 parent b6ffde4 commit 4ef5000
Show file tree
Hide file tree
Showing 24 changed files with 238 additions and 185 deletions.
2 changes: 1 addition & 1 deletion test/cache/repair/handles_failure_test.dart
Expand Up @@ -19,7 +19,7 @@ main() {
// Set up a cache with some packages.
d.dir(cachePath, [
d.dir('hosted', [
d.async(port.then((p) => d.dir('localhost%58$p', [
d.async(globalServer.port.then((p) => d.dir('localhost%58$p', [
d.dir("foo-1.2.3", [
d.libPubspec("foo", "1.2.3"),
d.file("broken.txt")
Expand Down
2 changes: 1 addition & 1 deletion test/cache/repair/reinstalls_hosted_packages_test.dart
Expand Up @@ -18,7 +18,7 @@ main() {
// Set up a cache with some broken packages.
d.dir(cachePath, [
d.dir('hosted', [
d.async(port.then((p) => d.dir('localhost%58$p', [
d.async(globalServer.port.then((p) => d.dir('localhost%58$p', [
d.dir("foo-1.2.3", [
d.libPubspec("foo", "1.2.3"),
d.file("broken.txt")
Expand Down
2 changes: 1 addition & 1 deletion test/descriptor.dart
Expand Up @@ -153,7 +153,7 @@ Descriptor cacheDir(Map packages, {bool includePubspecs: false}) {
Descriptor hostedCache(Iterable<Descriptor> contents) {
return dir(cachePath, [
dir('hosted', [
async(port.then((p) => dir('localhost%58$p', contents)))
async(globalServer.port.then((p) => dir('localhost%58$p', contents)))
])
]);
}
Expand Down
124 changes: 124 additions & 0 deletions test/descriptor_server.dart
@@ -0,0 +1,124 @@
// 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.

import 'dart:async';
import 'dart:io';

import 'package:path/path.dart' as p;
import 'package:pub/src/utils.dart';
import 'package:scheduled_test/scheduled_test.dart' hide fail;
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as shelf_io;

import 'descriptor.dart' as d;

/// The global [DescriptorServer] that's used by default.
///
/// `null` if there's no global server in use. This can be set to replace the
/// existing global server.
DescriptorServer get globalServer => _globalServer;
set globalServer(DescriptorServer value) {
if (_globalServer == null) {
currentSchedule.onComplete.schedule(() {
_globalServer = null;
}, 'clearing the global server');
} else {
_globalServer.close();
}

_globalServer = value;
}
DescriptorServer _globalServer;

/// Creates a global [DescriptorServer] to serve [contents] as static files.
///
/// This server will exist only for the duration of the pub run. It's accessible
/// via [server]. Subsequent calls to [serve] replace the previous server.
void serve([List<d.Descriptor> contents]) {
globalServer = new DescriptorServer(contents);
}

/// Like [serve], but reports an error if a request ever comes in to the server.
void serveErrors() {
globalServer = new DescriptorServer.errors();
}

class DescriptorServer {
/// The server, or `null` before it's available.
HttpServer _server;

/// A future that will complete to the port used for the server.
Future<int> get port => _portCompleter.future;
final _portCompleter = new Completer<int>();

/// Gets the list of paths that have been requested from the server.
Future<List<String>> get requestedPaths =>
schedule(() => _requestedPaths.toList(),
"get previous network requests");

/// The list of paths that have been requested from this server.
final _requestedPaths = <String>[];

/// Creates an HTTP server to serve [contents] as static files.
///
/// This server exists only for the duration of the pub run. Subsequent calls
/// to [serve] replace the previous server.
DescriptorServer([List<d.Descriptor> contents]) {
var baseDir = d.dir("serve-dir", contents);

schedule(() async {
_server = await shelf_io.serve((request) async {
var path = p.posix.fromUri(request.url.path);
_requestedPaths.add(path);

try {
var stream = await validateStream(baseDir.load(path));
return new shelf.Response.ok(stream);
} catch (_) {
return new shelf.Response.notFound('File "$path" not found.');
}
}, 'localhost', 0);

_portCompleter.complete(_server.port);
_closeOnComplete();
}, 'starting a server serving:\n${baseDir.describe()}');
}

/// Creates a server that reports an error if a request is ever received.
DescriptorServer.errors() {
schedule(() async {
_server = await shelf_io.serve((request) {
fail("The HTTP server received an unexpected request:\n"
"${request.method} ${request.requestedUri}");
return new shelf.Response.forbidden(null);
}, 'localhost', 0);

_portCompleter.complete(_server.port);
_closeOnComplete();
});
}

/// Schedules [requestedPaths] to be emptied.
void clearRequestedPaths() {
schedule(() {
_requestedPaths.clear();
}, "clearing requested paths");
}

/// Schedules the closing of this server.
void close() {
schedule(() async {
if (_server == null) return;
await _server.close();
}, "closing DescriptorServer");
}

/// Schedules this server to close once the schedule is done.
void _closeOnComplete() {
currentSchedule.onComplete.schedule(() async {
if (_server == null) return;
await _server.close();
}, "closing DescriptorServer");
}
}
2 changes: 1 addition & 1 deletion test/downgrade/unlock_dependers_test.dart
Expand Up @@ -22,7 +22,7 @@ main() {
"bar": "2.0.0"
}).validate();

servePackages((builder) {
globalPackageServer.add((builder) {
builder.serve("foo", "1.0.0", deps: {"bar": "any"});
builder.serve("bar", "1.0.0");
});
Expand Down
2 changes: 1 addition & 1 deletion test/downgrade/unlock_if_necessary_test.dart
Expand Up @@ -22,7 +22,7 @@ main() {
"foo_dep": "2.0.0"
}).validate();

servePackages((builder) {
globalPackageServer.add((builder) {
builder.serve("foo", "1.0.0", deps: {"foo_dep": "<2.0.0"});
builder.serve("foo_dep", "1.0.0");
});
Expand Down
4 changes: 2 additions & 2 deletions test/get/cache_transformed_dependency_test.dart
Expand Up @@ -203,7 +203,7 @@ main() {
d.appDir({"foo": "1.2.3"}).create();
pubGet(output: contains("Precompiled foo."));

servePackages((builder) => builder.serve("bar", "6.0.0"));
globalPackageServer.add((builder) => builder.serve("bar", "6.0.0"));
pubUpgrade(output: contains("Precompiled foo."));
});

Expand All @@ -227,7 +227,7 @@ main() {
d.appDir({"foo": "1.2.3"}).create();
pubGet(output: contains("Precompiled foo."));

servePackages((builder) => builder.serve("bar", "6.0.0"));
globalPackageServer.add((builder) => builder.serve("bar", "6.0.0"));
pubUpgrade(output: isNot(contains("Precompiled foo.")));
});

Expand Down
4 changes: 2 additions & 2 deletions test/get/hosted/avoid_network_requests_test.dart
Expand Up @@ -27,7 +27,7 @@ main() {

// Clear the cache. We don't care about anything that was served during
// the initial get.
getRequestedPaths();
globalServer.clearRequestedPaths();

// Add "bar" to the dependencies.
d.appDir({
Expand All @@ -45,7 +45,7 @@ main() {

// The get should not have done any network requests since the lock file is
// up to date.
getRequestedPaths().then((paths) {
globalServer.requestedPaths.then((paths) {
expect(paths, unorderedEquals([
// Bar should be requested because it's new, but not foo.
"api/packages/bar",
Expand Down
4 changes: 2 additions & 2 deletions test/get/hosted/cached_pubspec_test.dart
Expand Up @@ -18,7 +18,7 @@ main() {

// Clear the cache. We don't care about anything that was served during
// the initial get.
getRequestedPaths();
globalServer.clearRequestedPaths();

d.cacheDir({"foo": "1.2.3"}).validate();
d.packagesDir({"foo": "1.2.3"}).validate();
Expand All @@ -27,7 +27,7 @@ main() {
pubGet();

// The get should not have requested the pubspec since it's local already.
getRequestedPaths().then((paths) {
globalServer.requestedPaths.then((paths) {
expect(paths, isNot(contains("packages/foo/versions/1.2.3.yaml")));
});
});
Expand Down
Expand Up @@ -24,7 +24,7 @@ main() {

// Clear the cache. We don't care about anything that was served during
// the initial get.
getRequestedPaths();
globalServer.clearRequestedPaths();

// Run the solver again now that it's cached.
pubGet();
Expand All @@ -34,7 +34,7 @@ main() {

// The get should not have done any network requests since the lock file is
// up to date.
getRequestedPaths().then((paths) {
globalServer.requestedPaths.then((paths) {
expect(paths, isEmpty);
});
});
Expand Down
2 changes: 1 addition & 1 deletion test/get/hosted/stay_locked_if_compatible_test.dart
Expand Up @@ -16,7 +16,7 @@ main() {

d.packagesDir({"foo": "1.0.0"}).validate();

servePackages((builder) => builder.serve("foo", "1.0.1"));
globalPackageServer.add((builder) => builder.serve("foo", "1.0.1"));

d.appDir({"foo": ">=1.0.0"}).create();

Expand Down
2 changes: 1 addition & 1 deletion test/get/hosted/stay_locked_if_new_is_satisfied_test.dart
Expand Up @@ -24,7 +24,7 @@ main() {
"baz": "1.0.0"
}).validate();

servePackages((builder) {
globalPackageServer.add((builder) {
builder.serve("foo", "2.0.0", deps: {"bar": "<3.0.0"});
builder.serve("bar", "2.0.0", deps: {"baz": "<3.0.0"});
builder.serve("baz", "2.0.0");
Expand Down
2 changes: 1 addition & 1 deletion test/get/hosted/stay_locked_test.dart
Expand Up @@ -25,7 +25,7 @@ main() {
schedule(() => deleteEntry(path.join(sandboxDir, packagesPath)));

// Start serving a newer package as well.
servePackages((builder) => builder.serve("foo", "1.0.1"));
globalPackageServer.add((builder) => builder.serve("foo", "1.0.1"));

// This shouldn't upgrade the foo dependency due to the lockfile.
pubGet();
Expand Down
2 changes: 1 addition & 1 deletion test/get/hosted/unlock_if_incompatible_test.dart
Expand Up @@ -15,7 +15,7 @@ main() {
pubGet();

d.packagesDir({"foo": "1.0.0"}).validate();
servePackages((builder) => builder.serve("foo", "1.0.1"));
globalPackageServer.add((builder) => builder.serve("foo", "1.0.1"));
d.appDir({"foo": ">1.0.0"}).create();

pubGet();
Expand Down
2 changes: 1 addition & 1 deletion test/get/hosted/unlock_if_new_is_unsatisfied_test.dart
Expand Up @@ -26,7 +26,7 @@ main() {
"qux": "1.0.0"
}).validate();

servePackages((builder) {
globalPackageServer.add((builder) {
builder.serve("foo", "2.0.0", deps: {"bar": "<3.0.0"});
builder.serve("bar", "2.0.0", deps: {"baz": "<3.0.0"});
builder.serve("baz", "2.0.0", deps: {"qux": "<3.0.0"});
Expand Down
2 changes: 1 addition & 1 deletion test/get/hosted/unlock_if_version_doesnt_exist_test.dart
Expand Up @@ -20,7 +20,7 @@ main() {

schedule(() => deleteEntry(p.join(sandboxDir, cachePath)));

servePackages((builder) => builder.serve("foo", "1.0.1"), replace: true);
globalPackageServer.replace((builder) => builder.serve("foo", "1.0.1"));
pubGet();
d.packagesDir({"foo": "1.0.1"}).validate();
});
Expand Down
5 changes: 3 additions & 2 deletions test/list_package_dirs/lists_dependency_directories_test.dart
Expand Up @@ -34,8 +34,9 @@ main() {
outputJson: {
"packages": {
"foo": path.join(sandboxDir, "foo", "lib"),
"bar": port.then((p) => path.join(sandboxDir, cachePath, "hosted",
"localhost%58$p", "bar-1.0.0", "lib")),
"bar": globalServer.port.then(
(p) => path.join(sandboxDir, cachePath, "hosted",
"localhost%58$p", "bar-1.0.0", "lib")),
"myapp": canonicalize(path.join(sandboxDir, appPath, "lib"))
},
"input_files": [
Expand Down

0 comments on commit 4ef5000

Please sign in to comment.