Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(254)

Side by Side Diff: utils/tests/pub/test_pub.dart

Issue 12316036: Merge IO v2 branch to bleeding edge (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased to r18818 Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/tests/pub/pub_uploader_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub 5 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub
6 /// tests are integration tests that stage some stuff on the file system, run 6 /// tests are integration tests that stage some stuff on the file system, run
7 /// pub, and then validate the results. This library provides an API to build 7 /// pub, and then validate the results. This library provides an API to build
8 /// tests like that. 8 /// tests like that.
9 library test_pub; 9 library test_pub;
10 10
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 95
96 /// Creates an HTTP server to serve [contents] as static files. This server will 96 /// Creates an HTTP server to serve [contents] as static files. This server will
97 /// exist only for the duration of the pub run. 97 /// exist only for the duration of the pub run.
98 /// 98 ///
99 /// Subsequent calls to [serve] will replace the previous server. 99 /// Subsequent calls to [serve] will replace the previous server.
100 void serve([List<Descriptor> contents]) { 100 void serve([List<Descriptor> contents]) {
101 var baseDir = dir("serve-dir", contents); 101 var baseDir = dir("serve-dir", contents);
102 102
103 _schedule((_) { 103 _schedule((_) {
104 return _closeServer().then((_) { 104 return _closeServer().then((_) {
105 _server = new HttpServer(); 105 return HttpServer.bind("127.0.0.1", 0).then((server) {
106 _server.defaultRequestHandler = (request, response) { 106 _server = server;
107 var path = request.uri.replaceFirst("/", "").split("/"); 107 server.listen((request) {
108 response.persistentConnection = false; 108 var response = request.response;
109 var stream; 109 var path = request.uri.path.replaceFirst("/", "").split("/");
110 try { 110 response.persistentConnection = false;
111 stream = baseDir.load(path); 111 var stream;
112 } catch (e) { 112 try {
113 response.statusCode = 404; 113 stream = baseDir.load(path);
114 response.contentLength = 0; 114 } catch (e) {
115 response.outputStream.close(); 115 response.statusCode = 404;
116 return; 116 response.contentLength = 0;
117 } 117 response.close();
118 return;
119 }
118 120
119 stream.toBytes().then((data) { 121 stream.toBytes().then((data) {
120 response.statusCode = 200; 122 response.statusCode = 200;
121 response.contentLength = data.length; 123 response.contentLength = data.length;
122 response.outputStream.write(data); 124 response.add(data);
123 response.outputStream.close(); 125 response.close();
124 }).catchError((e) { 126 }).catchError((e) {
125 print("Exception while handling ${request.uri}: $e"); 127 print("Exception while handling ${request.uri}: $e");
126 response.statusCode = 500; 128 response.statusCode = 500;
127 response.reasonPhrase = e.message; 129 response.reasonPhrase = e.message;
128 response.outputStream.close(); 130 response.close();
131 });
129 }); 132 });
130 }; 133 _portCompleter.complete(_server.port);
131 _server.listen("127.0.0.1", 0); 134 _scheduleCleanup((_) => _closeServer());
132 _portCompleter.complete(_server.port); 135 return null;
133 _scheduleCleanup((_) => _closeServer()); 136 });
134 return null;
135 }); 137 });
136 }); 138 });
137 } 139 }
138 140
139 /// Closes [_server]. Returns a [Future] that will complete after the [_server] 141 /// Closes [_server]. Returns a [Future] that will complete after the [_server]
140 /// is closed. 142 /// is closed.
141 Future _closeServer() { 143 Future _closeServer() {
142 if (_server == null) return new Future.immediate(null); 144 if (_server == null) return new Future.immediate(null);
143 _server.close(); 145 _server.close();
144 _server = null; 146 _server = null;
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 462
461 /// The path of the packages directory in the mock app used for tests. Relative 463 /// The path of the packages directory in the mock app used for tests. Relative
462 /// to the sandbox directory. 464 /// to the sandbox directory.
463 final String packagesPath = "$appPath/packages"; 465 final String packagesPath = "$appPath/packages";
464 466
465 /// The type for callbacks that will be fired during [schedulePub]. Takes the 467 /// The type for callbacks that will be fired during [schedulePub]. Takes the
466 /// sandbox directory as a parameter. 468 /// sandbox directory as a parameter.
467 typedef Future _ScheduledEvent(String parentDir); 469 typedef Future _ScheduledEvent(String parentDir);
468 470
469 /// The list of events that are scheduled to run as part of the test case. 471 /// The list of events that are scheduled to run as part of the test case.
470 List<_ScheduledEvent> _scheduled; 472 Queue<_ScheduledEvent> _scheduled;
471 473
472 /// The list of events that are scheduled to run after the test case, even if 474 /// The list of events that are scheduled to run after the test case, even if
473 /// it failed. 475 /// it failed.
474 List<_ScheduledEvent> _scheduledCleanup; 476 Queue<_ScheduledEvent> _scheduledCleanup;
475 477
476 /// The list of events that are scheduled to run after the test case only if it 478 /// The list of events that are scheduled to run after the test case only if it
477 /// failed. 479 /// failed.
478 List<_ScheduledEvent> _scheduledOnException; 480 Queue<_ScheduledEvent> _scheduledOnException;
479 481
480 /// Set to true when the current batch of scheduled events should be aborted. 482 /// Set to true when the current batch of scheduled events should be aborted.
481 bool _abortScheduled = false; 483 bool _abortScheduled = false;
482 484
483 /// The time (in milliseconds) to wait for the entire scheduled test to 485 /// The time (in milliseconds) to wait for the entire scheduled test to
484 /// complete. 486 /// complete.
485 final _TIMEOUT = 30000; 487 final _TIMEOUT = 30000;
486 488
487 /// Defines an integration test. The [body] should schedule a series of 489 /// Defines an integration test. The [body] should schedule a series of
488 /// operations which will be run asynchronously. 490 /// operations which will be run asynchronously.
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
697 /// Note that this will only affect HTTP requests made via http.dart in the 699 /// Note that this will only affect HTTP requests made via http.dart in the
698 /// parent process. 700 /// parent process.
699 void useMockClient(MockClient client) { 701 void useMockClient(MockClient client) {
700 var oldInnerClient = httpClient.inner; 702 var oldInnerClient = httpClient.inner;
701 httpClient.inner = client; 703 httpClient.inner = client;
702 _scheduleCleanup((_) { 704 _scheduleCleanup((_) {
703 httpClient.inner = oldInnerClient; 705 httpClient.inner = oldInnerClient;
704 }); 706 });
705 } 707 }
706 708
707 Future _runScheduled(List<_ScheduledEvent> scheduled) { 709 Future _runScheduled(Queue<_ScheduledEvent> scheduled) {
708 if (scheduled == null) return new Future.immediate(null); 710 if (scheduled == null) return new Future.immediate(null);
709 var iterator = scheduled.iterator;
710 711
711 Future runNextEvent(_) { 712 Future runNextEvent(_) {
712 if (_abortScheduled || !iterator.moveNext()) { 713 if (_abortScheduled || scheduled.isEmpty) {
713 _abortScheduled = false; 714 _abortScheduled = false;
714 scheduled.clear();
715 return new Future.immediate(null); 715 return new Future.immediate(null);
716 } 716 }
717 717
718 var future = iterator.current(_sandboxDir); 718 var future = scheduled.removeFirst()(_sandboxDir);
719 if (future != null) { 719 if (future != null) {
720 return future.then(runNextEvent); 720 return future.then(runNextEvent);
721 } else { 721 } else {
722 return runNextEvent(null); 722 return runNextEvent(null);
723 } 723 }
724 } 724 }
725 725
726 return runNextEvent(null); 726 return runNextEvent(null);
727 } 727 }
728 728
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after
1148 /// Loads the contents of this tar file. 1148 /// Loads the contents of this tar file.
1149 ByteStream load(List<String> path) { 1149 ByteStream load(List<String> path) {
1150 if (!path.isEmpty) { 1150 if (!path.isEmpty) {
1151 throw "Can't load ${path.join('/')} from within $name: not a directory."; 1151 throw "Can't load ${path.join('/')} from within $name: not a directory.";
1152 } 1152 }
1153 1153
1154 var controller = new StreamController<List<int>>(); 1154 var controller = new StreamController<List<int>>();
1155 // TODO(nweiz): propagate any errors to the return value. See issue 3657. 1155 // TODO(nweiz): propagate any errors to the return value. See issue 3657.
1156 withTempDir((tempDir) { 1156 withTempDir((tempDir) {
1157 return create(tempDir).then((tar) { 1157 return create(tempDir).then((tar) {
1158 var sourceStream = new File(tar).openInputStream(); 1158 var sourceStream = new File(tar).openRead();
1159 return store(wrapInputStream(sourceStream), controller); 1159 return store(sourceStream, controller);
1160 }); 1160 });
1161 }); 1161 });
1162 return new ByteStream(controller.stream); 1162 return new ByteStream(controller.stream);
1163 } 1163 }
1164 } 1164 }
1165 1165
1166 /// A descriptor that validates that no file exists with the given name. 1166 /// A descriptor that validates that no file exists with the given name.
1167 class NothingDescriptor extends Descriptor { 1167 class NothingDescriptor extends Descriptor {
1168 NothingDescriptor(String name) : super(name); 1168 NothingDescriptor(String name) : super(name);
1169 1169
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
1493 /// The requests to be ignored. 1493 /// The requests to be ignored.
1494 final _ignored = new Set<Pair<String, String>>(); 1494 final _ignored = new Set<Pair<String, String>>();
1495 1495
1496 ScheduledServer._(this._server); 1496 ScheduledServer._(this._server);
1497 1497
1498 /// Creates a new server listening on an automatically-allocated port on 1498 /// Creates a new server listening on an automatically-allocated port on
1499 /// localhost. 1499 /// localhost.
1500 factory ScheduledServer() { 1500 factory ScheduledServer() {
1501 var scheduledServer; 1501 var scheduledServer;
1502 scheduledServer = new ScheduledServer._(_scheduleValue((_) { 1502 scheduledServer = new ScheduledServer._(_scheduleValue((_) {
1503 var server = new HttpServer(); 1503 return HttpServer.bind("127.0.0.1", 0).then((server) {
1504 server.defaultRequestHandler = scheduledServer._awaitHandle; 1504 server.listen(scheduledServer._awaitHandle);
1505 server.listen("127.0.0.1", 0); 1505 _scheduleCleanup((_) => server.close());
1506 _scheduleCleanup((_) => server.close()); 1506 return server;
1507 return new Future.immediate(server); 1507 });
1508 })); 1508 }));
1509 return scheduledServer; 1509 return scheduledServer;
1510 } 1510 }
1511 1511
1512 /// The port on which the server is listening. 1512 /// The port on which the server is listening.
1513 Future<int> get port => _server.then((s) => s.port); 1513 Future<int> get port => _server.then((s) => s.port);
1514 1514
1515 /// The base URL of the server, including its port. 1515 /// The base URL of the server, including its port.
1516 Future<Uri> get url => 1516 Future<Uri> get url =>
1517 port.then((p) => Uri.parse("http://localhost:$p")); 1517 port.then((p) => Uri.parse("http://localhost:$p"));
1518 1518
1519 /// Assert that the next request has the given [method] and [path], and pass 1519 /// Assert that the next request has the given [method] and [path], and pass
1520 /// it to [handler] to handle. If [handler] returns a [Future], wait until 1520 /// it to [handler] to handle. If [handler] returns a [Future], wait until
1521 /// it's completed to continue the schedule. 1521 /// it's completed to continue the schedule.
1522 void handle(String method, String path, 1522 void handle(String method, String path,
1523 Future handler(HttpRequest request, HttpResponse response)) { 1523 Future handler(HttpRequest request, HttpResponse response)) {
1524 var handlerCompleter = new Completer<Function>(); 1524 var handlerCompleter = new Completer<Function>();
1525 _scheduleValue((_) { 1525 _scheduleValue((_) {
1526 var requestCompleteCompleter = new Completer(); 1526 var requestCompleteCompleter = new Completer();
1527 handlerCompleter.complete((request, response) { 1527 handlerCompleter.complete((request, response) {
1528 expect(request.method, equals(method)); 1528 expect(request.method, equals(method));
1529 // TODO(nweiz): Use request.path once issue 7464 is fixed. 1529 expect(request.uri.path, equals(path));
1530 expect(Uri.parse(request.uri).path, equals(path));
1531 1530
1532 var future = handler(request, response); 1531 var future = handler(request, response);
1533 if (future == null) future = new Future.immediate(null); 1532 if (future == null) future = new Future.immediate(null);
1534 chainToCompleter(future, requestCompleteCompleter); 1533 chainToCompleter(future, requestCompleteCompleter);
1535 }); 1534 });
1536 return timeout(requestCompleteCompleter.future, 1535 return timeout(requestCompleteCompleter.future,
1537 _SCHEDULE_TIMEOUT, "waiting for $method $path"); 1536 _SCHEDULE_TIMEOUT, "waiting for $method $path");
1538 }); 1537 });
1539 _handlers.add(handlerCompleter.future); 1538 _handlers.add(handlerCompleter.future);
1540 } 1539 }
1541 1540
1542 /// Ignore all requests with the given [method] and [path]. If one is 1541 /// Ignore all requests with the given [method] and [path]. If one is
1543 /// received, don't respond to it. 1542 /// received, don't respond to it.
1544 void ignore(String method, String path) => 1543 void ignore(String method, String path) =>
1545 _ignored.add(new Pair(method, path)); 1544 _ignored.add(new Pair(method, path));
1546 1545
1547 /// Raises an error complaining of an unexpected request. 1546 /// Raises an error complaining of an unexpected request.
1548 void _awaitHandle(HttpRequest request, HttpResponse response) { 1547 void _awaitHandle(HttpRequest request) {
1549 if (_ignored.contains(new Pair(request.method, request.path))) return; 1548 HttpResponse response = request.response;
1549 if (_ignored.contains(new Pair(request.method, request.uri.path))) return;
1550 var future = timeout(defer(() { 1550 var future = timeout(defer(() {
1551 if (_handlers.isEmpty) { 1551 if (_handlers.isEmpty) {
1552 fail('Unexpected ${request.method} request to ${request.path}.'); 1552 fail('Unexpected ${request.method} request to ${request.uri.path}.');
1553 } 1553 }
1554 return _handlers.removeFirst(); 1554 return _handlers.removeFirst();
1555 }).then((handler) { 1555 }).then((handler) {
1556 handler(request, response); 1556 handler(request, response);
1557 }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} " 1557 }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} "
1558 "${request.path}"); 1558 "${request.uri.path}");
1559 expect(future, completes); 1559 expect(future, completes);
1560 } 1560 }
1561 } 1561 }
1562 1562
1563 /// Takes a simple data structure (composed of [Map]s, [List]s, scalar objects, 1563 /// Takes a simple data structure (composed of [Map]s, [List]s, scalar objects,
1564 /// and [Future]s) and recursively resolves all the [Future]s contained within. 1564 /// and [Future]s) and recursively resolves all the [Future]s contained within.
1565 /// Completes with the fully resolved structure. 1565 /// Completes with the fully resolved structure.
1566 Future _awaitObject(object) { 1566 Future _awaitObject(object) {
1567 // Unroll nested futures. 1567 // Unroll nested futures.
1568 if (object is Future) return object.then(_awaitObject); 1568 if (object is Future) return object.then(_awaitObject);
(...skipping 11 matching lines...) Expand all
1580 var map = {}; 1580 var map = {};
1581 for (var pair in resolvedPairs) { 1581 for (var pair in resolvedPairs) {
1582 map[pair.first] = pair.last; 1582 map[pair.first] = pair.last;
1583 } 1583 }
1584 return map; 1584 return map;
1585 }); 1585 });
1586 } 1586 }
1587 1587
1588 /// Schedules a callback to be called as part of the test case. 1588 /// Schedules a callback to be called as part of the test case.
1589 void _schedule(_ScheduledEvent event) { 1589 void _schedule(_ScheduledEvent event) {
1590 if (_scheduled == null) _scheduled = []; 1590 if (_scheduled == null) _scheduled = new Queue();
1591 _scheduled.add(event); 1591 _scheduled.addLast(event);
1592 } 1592 }
1593 1593
1594 /// Like [_schedule], but pipes the return value of [event] to a returned 1594 /// Like [_schedule], but pipes the return value of [event] to a returned
1595 /// [Future]. 1595 /// [Future].
1596 Future _scheduleValue(_ScheduledEvent event) { 1596 Future _scheduleValue(_ScheduledEvent event) {
1597 var completer = new Completer(); 1597 var completer = new Completer();
1598 _schedule((parentDir) { 1598 _schedule((parentDir) {
1599 chainToCompleter(event(parentDir), completer); 1599 chainToCompleter(event(parentDir), completer);
1600 return completer.future; 1600 return completer.future;
1601 }); 1601 });
1602 return completer.future; 1602 return completer.future;
1603 } 1603 }
1604 1604
1605 /// Schedules a callback to be called after the test case has completed, even 1605 /// Schedules a callback to be called after the test case has completed, even
1606 /// if it failed. 1606 /// if it failed.
1607 void _scheduleCleanup(_ScheduledEvent event) { 1607 void _scheduleCleanup(_ScheduledEvent event) {
1608 if (_scheduledCleanup == null) _scheduledCleanup = []; 1608 if (_scheduledCleanup == null) _scheduledCleanup = new Queue();
1609 _scheduledCleanup.add(event); 1609 _scheduledCleanup.addLast(event);
1610 } 1610 }
1611 1611
1612 /// Schedules a callback to be called after the test case has completed, but 1612 /// Schedules a callback to be called after the test case has completed, but
1613 /// only if it failed. 1613 /// only if it failed.
1614 void _scheduleOnException(_ScheduledEvent event) { 1614 void _scheduleOnException(_ScheduledEvent event) {
1615 if (_scheduledOnException == null) _scheduledOnException = []; 1615 if (_scheduledOnException == null) _scheduledOnException = new Queue();
1616 _scheduledOnException.add(event); 1616 _scheduledOnException.addLast(event);
1617 } 1617 }
1618 1618
1619 /// Like [expect], but for [Future]s that complete as part of the scheduled 1619 /// Like [expect], but for [Future]s that complete as part of the scheduled
1620 /// test. This is necessary to ensure that the exception thrown by the 1620 /// test. This is necessary to ensure that the exception thrown by the
1621 /// expectation failing is handled by the scheduler. 1621 /// expectation failing is handled by the scheduler.
1622 /// 1622 ///
1623 /// Note that [matcher] matches against the completed value of [actual], so 1623 /// Note that [matcher] matches against the completed value of [actual], so
1624 /// calling [completion] is unnecessary. 1624 /// calling [completion] is unnecessary.
1625 void expectLater(Future actual, matcher, {String reason, 1625 void expectLater(Future actual, matcher, {String reason,
1626 FailureHandler failureHandler, bool verbose: false}) { 1626 FailureHandler failureHandler, bool verbose: false}) {
1627 _schedule((_) { 1627 _schedule((_) {
1628 return actual.then((value) { 1628 return actual.then((value) {
1629 expect(value, matcher, reason: reason, failureHandler: failureHandler, 1629 expect(value, matcher, reason: reason, failureHandler: failureHandler,
1630 verbose: false); 1630 verbose: false);
1631 }); 1631 });
1632 }); 1632 });
1633 } 1633 }
OLDNEW
« no previous file with comments | « utils/tests/pub/pub_uploader_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698