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

Side by Side Diff: tools/testing/dart/browser_controller.dart

Issue 15567002: Added support for running dart2js tests on android devices (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 7 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 library browser; 4 library browser;
5 5
6 import "dart:async"; 6 import "dart:async";
7 import "dart:core"; 7 import "dart:core";
8 import "dart:io"; 8 import "dart:io";
9 9
10 import 'android.dart';
10 11
11 /** Class describing the interface for communicating with browsers. */ 12 /** Class describing the interface for communicating with browsers. */
12 class Browser { 13 abstract class Browser {
13 // Browsers actually takes a while to cleanup after itself when closing 14 // Browsers actually takes a while to cleanup after itself when closing
14 // Give it sufficient time to do that. 15 // Give it sufficient time to do that.
15 static final Duration killRepeatInternal = const Duration(seconds: 10); 16 static final Duration killRepeatInternal = const Duration(seconds: 10);
16 static final int killRetries = 5; 17 static final int killRetries = 5;
17 StringBuffer _stdout = new StringBuffer(); 18 StringBuffer _stdout = new StringBuffer();
18 StringBuffer _stderr = new StringBuffer(); 19 StringBuffer _stderr = new StringBuffer();
19 StringBuffer _usageLog = new StringBuffer(); 20 StringBuffer _usageLog = new StringBuffer();
20 // This function is called when the process is closed. 21 // This function is called when the process is closed.
21 // This is extracted to an external function so that we can do additional 22 // This is extracted to an external function so that we can do additional
22 // functionality when the process closes (cleanup and call onExit) 23 // functionality when the process closes (cleanup and call onExit)
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 }); 155 });
155 156
156 process.exitCode.then((exitCode) { 157 process.exitCode.then((exitCode) {
157 _logEvent("Browser closed with exitcode $exitCode"); 158 _logEvent("Browser closed with exitcode $exitCode");
158 if (_processClosed != null) _processClosed(); 159 if (_processClosed != null) _processClosed();
159 if (_cleanup != null) _cleanup(); 160 if (_cleanup != null) _cleanup();
160 if (onClose != null) onClose(exitCode); 161 if (onClose != null) onClose(exitCode);
161 }); 162 });
162 return true; 163 return true;
163 }).catchError((error) { 164 }).catchError((error) {
164 _logEvent("Running $binary $arguments failed with $error"); 165 _logEvent("Running $command $arguments failed with $error");
165 return false; 166 return false;
166 }); 167 });
167 } 168 }
168 169
169 /** 170 /**
170 * Get any stdout that the browser wrote during execution. 171 * Get any stdout that the browser wrote during execution.
171 */ 172 */
172 String get stdout => _stdout.toString(); 173 String get stdout => _stdout.toString();
173 String get stderr => _stderr.toString(); 174 String get stderr => _stderr.toString();
174 String get usageLog => _usageLog.toString(); 175 String get usageLog => _usageLog.toString();
175 176
176 String toString(); 177 String toString();
177 /** Starts the browser loading the given url */ 178 /** Starts the browser loading the given url */
178 Future<bool> start(String url); 179 Future<bool> start(String url);
179 } 180 }
180 181
181
182 class Chrome extends Browser { 182 class Chrome extends Browser {
183 /** 183 /**
184 * The binary used to run chrome - changing this can be nececcary for 184 * The binary used to run chrome - changing this can be nececcary for
185 * testing or using non standard chrome installation. 185 * testing or using non standard chrome installation.
186 */ 186 */
187 const String binary = "google-chrome"; 187 const String binary = "google-chrome";
188 188
189 Future<bool> start(String url) { 189 Future<bool> start(String url) {
190 _logEvent("Starting chrome browser on: $url"); 190 _logEvent("Starting chrome browser on: $url");
191 // Get the version and log that. 191 // Get the version and log that.
(...skipping 16 matching lines...) Expand all
208 }); 208 });
209 }).catchError((e) { 209 }).catchError((e) {
210 _logEvent("Running $binary --version failed with $e"); 210 _logEvent("Running $binary --version failed with $e");
211 return false; 211 return false;
212 }); 212 });
213 } 213 }
214 214
215 String toString() => "Chrome"; 215 String toString() => "Chrome";
216 } 216 }
217 217
218 class AndroidChrome extends Browser {
219 const String viewAction = 'android.intent.action.VIEW';
220 const String mainAction = 'android.intent.action.MAIN';
221 const String chromePackage = 'com.android.chrome';
222 const String browserPackage = 'com.android.browser';
223 const String firefoxPackage = 'org.mozilla.firefox';
224 const String turnScreenOnPackage = 'com.google.dart.turnscreenon';
225
226 AndroidEmulator _emulator;
227 AdbDevice _adbDevice;
228
229 AndroidChrome(this._adbDevice);
230
231 Future<bool> start(String url) {
232 var browserIntent = new Intent(
233 viewAction, browserPackage, '.BrowserActivity', url);
234 var chromeIntent = new Intent(viewAction, chromePackage, '.Main', url);
235 var firefoxIntent = new Intent(viewAction, firefoxPackage, '.App', url);
236 var turnScreenOnIntent =
237 new Intent(mainAction, turnScreenOnPackage, '.Main');
238
239 var chromeAPK = new Path(
240 'third_party/android_testing_resources/com.android.chrome-1.apk');
241 var turnScreenOnAPK = new Path(
242 'third_party/android_testing_resources/TurnScreenOn.apk');
243 var chromeConfDir = new Path(
244 'third_party/android_testing_resources/chrome_configuration');
245 var chromeConfDirRemote = new Path(
246 '/data/user/0/com.android.chrome/');
247
248 return _adbDevice.waitForBootCompleted().then((_) {
249 return _adbDevice.forceStop(chromeIntent.package);
250 }).then((_) {
251 return _adbDevice.killAll();
252 }).then((_) {
253 return _adbDevice.adbRoot();
254 }).then((_) {
255 return _adbDevice.installApk(turnScreenOnAPK);
256 }).then((_) {
257 return _adbDevice.installApk(chromeAPK);
258 }).then((_) {
259 return _adbDevice.pushData(chromeConfDir, chromeConfDirRemote);
260 }).then((_) {
261 return _adbDevice.chmod('777', chromeConfDirRemote);
262 }).then((_) {
263 return _adbDevice.startActivity(turnScreenOnIntent).then((_) => true);
264 }).then((_) {
265 return _adbDevice.startActivity(chromeIntent).then((_) => true);
266 });
267 }
268
269 Future<bool> close() {
270 if (_adbDevice != null) {
271 return _adbDevice.forceStop(chromePackage).then((_) {
272 return _adbDevice.killAll().then((_) => true);
273 });
274 }
275 return new Future.immediate(true);
276 }
277
278 String toString() => "chromeOnAndroid";
279 }
280
218 class Firefox extends Browser { 281 class Firefox extends Browser {
219 /** 282 /**
220 * The binary used to run firefox - changing this can be nececcary for 283 * The binary used to run firefox - changing this can be nececcary for
221 * testing or using non standard firefox installation. 284 * testing or using non standard firefox installation.
222 */ 285 */
223 const String binary = "firefox"; 286 const String binary = "firefox";
224 287
225 const String enablePopUp = 288 const String enablePopUp =
226 "user_pref(\"dom.disable_open_during_load\", false);"; 289 "user_pref(\"dom.disable_open_during_load\", false);";
227 290
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 } 326 }
264 327
265 328
266 /** 329 /**
267 * Describes the current state of a browser used for testing. 330 * Describes the current state of a browser used for testing.
268 */ 331 */
269 class BrowserTestingStatus { 332 class BrowserTestingStatus {
270 // TODO(ricow): Add prefetching to the browsers. We spend a lot of time waiting 333 // TODO(ricow): Add prefetching to the browsers. We spend a lot of time waiting
271 // for the next test. Handling timeouts is the hard part of this! 334 // for the next test. Handling timeouts is the hard part of this!
272 335
273
274 Browser browser; 336 Browser browser;
275 BrowserTest currentTest; 337 BrowserTest currentTest;
276 // This is currently not used for anything except for error reporting. 338 // This is currently not used for anything except for error reporting.
277 // Given the usefulness of this in debugging issues this should not be 339 // Given the usefulness of this in debugging issues this should not be
278 // removed even when we have really stable system. 340 // removed even when we have really stable system.
279 BrowserTest lastTest; 341 BrowserTest lastTest;
280 bool timeout = false; 342 bool timeout = false;
281 BrowserTestingStatus(Browser this.browser); 343 BrowserTestingStatus(Browser this.browser);
282 } 344 }
283 345
(...skipping 21 matching lines...) Expand all
305 } 367 }
306 368
307 369
308 /** 370 /**
309 * Encapsulates all the functionality for running tests in browsers. 371 * Encapsulates all the functionality for running tests in browsers.
310 * The interface is rather simple. After starting the runner tests 372 * The interface is rather simple. After starting the runner tests
311 * are simply added to the queue and a the supplied callbacks are called 373 * are simply added to the queue and a the supplied callbacks are called
312 * whenever a test completes. 374 * whenever a test completes.
313 */ 375 */
314 class BrowserTestRunner { 376 class BrowserTestRunner {
377 String local_ip;
378 String browserName;
315 int maxNumBrowsers; 379 int maxNumBrowsers;
316 String browserName;
317 380
318 bool underTermination = false; 381 bool underTermination = false;
319 382
320 List<BrowserTest> testQueue = new List<BrowserTest>(); 383 List<BrowserTest> testQueue = new List<BrowserTest>();
321 Map<String, BrowserTestingStatus> browserStatus = 384 Map<String, BrowserTestingStatus> browserStatus =
322 new Map<String, BrowserTestingStatus>(); 385 new Map<String, BrowserTestingStatus>();
386
387 var adbDeviceMapping = new Map<String, AdbDevice>();
323 // This cache is used to guarantee that we never see double reporting. 388 // This cache is used to guarantee that we never see double reporting.
324 // If we do we need to provide developers with this information. 389 // If we do we need to provide developers with this information.
325 // We don't add urls to the cache until we have run it. 390 // We don't add urls to the cache until we have run it.
326 Map<int, String> testCache = new Map<int, String>(); 391 Map<int, String> testCache = new Map<int, String>();
327 List<int> doubleReportingTests = new List<int>(); 392 List<int> doubleReportingTests = new List<int>();
328 393
329 BrowserTestingServer testingServer; 394 BrowserTestingServer testingServer;
330 395
331 BrowserTestRunner(String this.browserName, int this.maxNumBrowsers); 396 BrowserTestRunner(this.local_ip, this.browserName, this.maxNumBrowsers);
332 397
333 Future<bool> start() { 398 Future<bool> start() {
334 testingServer = new BrowserTestingServer(); 399 testingServer = new BrowserTestingServer(local_ip);
335 return testingServer.start().then((_) { 400 return testingServer.start().then((_) {
336 testingServer.testDoneCallBack = handleResults; 401 testingServer.testDoneCallBack = handleResults;
337 testingServer.nextTestCallBack = getNextTest; 402 testingServer.nextTestCallBack = getNextTest;
338 var futures = []; 403 return getBrowsers().then((browsers) {
339 for (int i = 0; i < maxNumBrowsers; i++) { 404 var futures = [];
340 var browser = getInstance(); 405 for (var browser in browsers) {
341 var id = "BROWSER$i"; 406 var url = testingServer.getDriverUrl(browser.id);
342 // We store this in case we need to kill the browser. 407 var future = browser.start(url).then((success) {
343 browser.id = id; 408 if (success) {
ricow1 2013/05/22 13:13:37 indentation
kustermann 2013/05/22 15:32:41 Done.
344 var future = 409 browserStatus[browser.id] = new BrowserTestingStatus(browser);
345 browser.start(testingServer.getDriverUrl(id)).then((success) { 410 }
346 if (success) { 411 return success;
347 browserStatus[id] = new BrowserTestingStatus(browser); 412 });
348 } 413 futures.add(future);
349 return success; 414 }
350 }); 415 return Future.wait(futures).then((values) {
351 futures.add(future); 416 return !values.contains(false);
352 } 417 });
353 return Future.wait(futures).then((values) {
354 return !values.contains(false);
355 }); 418 });
356 }); 419 });
357 } 420 }
358 421
422 Future<List<Browser>> getBrowsers() {
ricow1 2013/05/22 13:13:37 I think this is rather hackish, how about this: Th
kustermann 2013/05/22 15:32:41 We've to determine the number of browsers before w
423 var browsersCompleter = new Completer();
424 if (browserName == 'chromeOnAndroid') {
425 AdbHelper.listDevices().then((deviceIds) {
426 if (deviceIds.length > 0) {
427 var browsers = [];
428 for (int i = 0; i < deviceIds.length; i++) {
429 var id = "BROWSER$i";
430 var device = new AdbDevice(deviceIds[i]);
431 adbDeviceMapping[id] = device;
432 var browser = new AndroidChrome(device);
433 browsers.add(browser);
434 // We store this in case we need to kill the browser.
435 browser.id = id;
436 }
437 browsersCompleter.complete(browsers);
438 } else {
439 throw new StateError("No android devices found.");
440 }
441 });
442 } else {
443 var browsers = [];
444 for (int i = 0; i < maxNumBrowsers; i++) {
445 var id = "BROWSER$i";
446 var browser = getInstance();
447 browsers.add(browser);
448 // We store this in case we need to kill the browser.
449 browser.id = id;
450 }
451 browsersCompleter.complete(browsers);
452 }
453 return browsersCompleter.future;
454 }
455
359 var timedOut = []; 456 var timedOut = [];
360 457
361 void handleResults(String browserId, String output, int testId) { 458 void handleResults(String browserId, String output, int testId) {
362 var status = browserStatus[browserId]; 459 var status = browserStatus[browserId];
363 if (testCache.containsKey(testId)) { 460 if (testCache.containsKey(testId)) {
364 doubleReportingTests.add(testId); 461 doubleReportingTests.add(testId);
365 return; 462 return;
366 } 463 }
367 464
368 if (status.timeout) { 465 if (status.timeout) {
(...skipping 28 matching lines...) Expand all
397 // We could be smarter here, but it does not seems like it is worth it. 494 // We could be smarter here, but it does not seems like it is worth it.
398 status.timeout = true; 495 status.timeout = true;
399 timedOut.add(status.currentTest.url); 496 timedOut.add(status.currentTest.url);
400 var id = status.browser.id; 497 var id = status.browser.id;
401 status.browser.close().then((closed) { 498 status.browser.close().then((closed) {
402 if (!closed) { 499 if (!closed) {
403 // Very bad, we could not kill the browser. 500 // Very bad, we could not kill the browser.
404 print("could not kill browser $id"); 501 print("could not kill browser $id");
405 return; 502 return;
406 } 503 }
407 // Start the new browser first 504 var browser;
408 var browser = getInstance(); 505 if (browserName == 'chromeOnAndroid') {
506 browser = new AndroidChrome(adbDeviceMapping[id]);
507 } else {
508 browser = getInstance();
509 }
409 browser.start(testingServer.getDriverUrl(id)).then((success) { 510 browser.start(testingServer.getDriverUrl(id)).then((success) {
410 // We may have started terminating in the mean time. 511 // We may have started terminating in the mean time.
411 if (underTermination) { 512 if (underTermination) {
412 browser.close().then((success) { 513 browser.close().then((success) {
413 // We should never hit this, print it out. 514 // We should never hit this, print it out.
414 if (!success) { 515 if (!success) {
415 print("Could not kill browser ($id) started due to timeout"); 516 print("Could not kill browser ($id) started due to timeout");
416 } 517 }
417 }); 518 });
418 return; 519 return;
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 if (browserName == "chrome") { 593 if (browserName == "chrome") {
493 return new Chrome(); 594 return new Chrome();
494 } else if (browserName == "ff") { 595 } else if (browserName == "ff") {
495 return new Firefox(); 596 return new Firefox();
496 } 597 }
497 throw "Non supported browser for browser controller"; 598 throw "Non supported browser for browser controller";
498 } 599 }
499 } 600 }
500 601
501 class BrowserTestingServer { 602 class BrowserTestingServer {
502 const String server = "127.0.0.1";
503
504 /// Interface of the testing server: 603 /// Interface of the testing server:
505 /// 604 ///
506 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch 605 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch
507 /// and run tests ... 606 /// and run tests ...
508 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id" 607 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id"
509 /// where url is the test to run, and id is the id of the test. 608 /// where url is the test to run, and id is the id of the test.
510 /// If there are currently no available tests the waitSignal is send 609 /// If there are currently no available tests the waitSignal is send
511 /// back. If we are in the process of terminating the terminateSignal 610 /// back. If we are in the process of terminating the terminateSignal
512 /// is send back and the browser will stop requesting new tasks. 611 /// is send back and the browser will stop requesting new tasks.
513 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed 612 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed
514 /// test 613 /// test
515 614
615 final String local_ip;
516 616
517 const String driverPath = "/driver"; 617 const String driverPath = "/driver";
518 const String nextTestPath = "/next_test"; 618 const String nextTestPath = "/next_test";
519 const String reportPath = "/report"; 619 const String reportPath = "/report";
520 const String waitSignal = "WAIT"; 620 const String waitSignal = "WAIT";
521 const String terminateSignal = "TERMINATE"; 621 const String terminateSignal = "TERMINATE";
522 622
523 var testCount = 0; 623 var testCount = 0;
524 var httpServer; 624 var httpServer;
525 bool underTermination = false; 625 bool underTermination = false;
526 626
527 Function testDoneCallBack; 627 Function testDoneCallBack;
528 Function nextTestCallBack; 628 Function nextTestCallBack;
529 629
630 BrowserTestingServer(this.local_ip);
631
530 Future start() { 632 Future start() {
531 return HttpServer.bind(server, 0).then((createdServer) { 633 return HttpServer.bind(local_ip, 0).then((createdServer) {
532 httpServer = createdServer; 634 httpServer = createdServer;
533 void handler(HttpRequest request) { 635 void handler(HttpRequest request) {
534 if (request.uri.path.startsWith(reportPath)) { 636 if (request.uri.path.startsWith(reportPath)) {
535 var browserId = request.uri.path.substring(reportPath.length + 1); 637 var browserId = request.uri.path.substring(reportPath.length + 1);
536 var testId = int.parse(request.queryParameters["id"].split("=")[1]); 638 var testId = int.parse(request.queryParameters["id"].split("=")[1]);
537 639
538 handleReport(request, browserId, testId); 640 handleReport(request, browserId, testId);
539 // handleReport will asynchroniously fetch the data and will handle 641 // handleReport will asynchroniously fetch the data and will handle
540 // the closing of the streams. 642 // the closing of the streams.
541 return; 643 return;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 } 695 }
594 } 696 }
595 697
596 String getDriverUrl(String browserId) { 698 String getDriverUrl(String browserId) {
597 if (httpServer == null) { 699 if (httpServer == null) {
598 print("Bad browser testing server, you are not started yet. Can't " 700 print("Bad browser testing server, you are not started yet. Can't "
599 "produce driver url"); 701 "produce driver url");
600 exit(1); 702 exit(1);
601 // This should never happen - exit immediately; 703 // This should never happen - exit immediately;
602 } 704 }
603 return "http://$server:${httpServer.port}/driver/$browserId"; 705 return "http://$local_ip:${httpServer.port}/driver/$browserId";
604 } 706 }
605 707
606 708
607 String getDriverPage(String browserId) { 709 String getDriverPage(String browserId) {
608 String driverContent = """ 710 String driverContent = """
609 <!DOCTYPE html><html> 711 <!DOCTYPE html><html>
610 <head> 712 <head>
611 <title>Driving page</title> 713 <title>Driving page</title>
612 <script type='text/javascript'> 714 <script type='text/javascript'>
613 var number_of_tests = 0; 715 var number_of_tests = 0;
716 var processed_ids = {};
614 var current_id; 717 var current_id;
615 var testing_window; 718 var testing_window;
616 var last_reported_id;
617 719
618 function newTaskHandler() { 720 function newTaskHandler() {
619 if (this.readyState == this.DONE) { 721 if (this.readyState == this.DONE) {
620 if (this.status == 200) { 722 if (this.status == 200) {
621 if (this.responseText == '$waitSignal') { 723 if (this.responseText == '$waitSignal') {
622 setTimeout(getNextTask, 500); 724 setTimeout(getNextTask, 500);
623 } else if (this.responseText == '$terminateSignal') { 725 } else if (this.responseText == '$terminateSignal') {
624 // Don't do anything, we will be killed shortly. 726 // Don't do anything, we will be killed shortly.
625 } else { 727 } else {
626 // TODO(ricow): Do something more clever here. 728 // TODO(ricow): Do something more clever here.
627 if (nextTask != undefined) alert('This is really bad'); 729 if (nextTask != undefined) alert('This is really bad');
628 // The task is send to us as: 730 // The task is send to us as:
629 // URL#ID 731 // URL#ID
630 var split = this.responseText.split('#'); 732 var split = this.responseText.split('#');
631 var nextTask = split[0]; 733 var nextTask = split[0];
632 current_id = split[1]; 734 if (testing_window != undefined) {
633 run(nextTask); 735 testing_window.location = '_blank';
736 }
737 function doAfterEmptyEventLoop() {
738 current_id = split[1];
739 processed_ids[current_id] = 0;
740 run(nextTask);
741 }
742 setTimeout(doAfterEmptyEventLoop(), 0);
634 } 743 }
635 } else { 744 } else {
636 // We are basically in trouble - do something clever. 745 // We are basically in trouble - do something clever.
637 } 746 }
638 } 747 }
639 } 748 }
640 749
641 function getNextTask() { 750 function getNextTask() {
642 var client = new XMLHttpRequest(); 751 var client = new XMLHttpRequest();
643 client.onreadystatechange = newTaskHandler; 752 client.onreadystatechange = newTaskHandler;
644 client.open('GET', '$nextTestPath/$browserId'); 753 client.open('GET', '$nextTestPath/$browserId');
645 client.send(); 754 client.send();
646 } 755 }
647 756
648 function run(url) { 757 function run(url) {
649 number_of_tests++; 758 number_of_tests++;
650 document.getElementById('number').innerHTML = number_of_tests; 759 document.getElementById('number').innerHTML = number_of_tests;
651 if (testing_window == undefined) { 760 if (testing_window == undefined) {
652 testing_window = window.open(url); 761 testing_window = window.open(url);
653 } else { 762 } else {
654 testing_window.location = url; 763 testing_window.location = url;
655 } 764 }
656 } 765 }
657 766
658 function reportMessage(msg) { 767 function reportMessage(msg) {
659 var client = new XMLHttpRequest(); 768 var client = new XMLHttpRequest();
660 function handleReady() { 769 function handleReady() {
661 if (this.readyState == this.DONE) { 770 if (this.readyState == this.DONE) {
662 if (current_id != last_reported_id) { 771 if (processed_ids[current_id] == 0) {
663 getNextTask(); 772 getNextTask();
664 last_reported_id = current_id; 773 processed_ids[current_id] = 1;
665 } 774 }
666 } 775 }
667 } 776 }
668 client.onreadystatechange = handleReady; 777 client.onreadystatechange = handleReady;
669 client.open('POST', '$reportPath/${browserId}?id=' + current_id); 778 client.open('POST', '$reportPath/${browserId}?id=' + current_id);
670 client.setRequestHeader('Content-type', 779 client.setRequestHeader('Content-type',
671 'application/x-www-form-urlencoded'); 780 'application/x-www-form-urlencoded');
672 client.send(msg); 781 client.send(msg);
673 // TODO(ricow) add error handling to somehow report the fact that 782 // TODO(ricow) add error handling to somehow report the fact that
674 // we could not send back a result. 783 // we could not send back a result.
(...skipping 13 matching lines...) Expand all
688 </script> 797 </script>
689 </head> 798 </head>
690 <body> 799 <body>
691 Dart test driver, number of tests: <div id="number"></div> 800 Dart test driver, number of tests: <div id="number"></div>
692 </body> 801 </body>
693 </html> 802 </html>
694 """; 803 """;
695 return driverContent; 804 return driverContent;
696 } 805 }
697 } 806 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698