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

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

Issue 632283002: Add support in test scripts backend for simple HTML tests. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add DOM to status and periodic status messages. Created 6 years, 2 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 | « no previous file | tools/testing/dart/test_controller.js » ('j') | 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) 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:convert" show LineSplitter, UTF8; 7 import "dart:convert" show LineSplitter, UTF8, JSON;
8 import "dart:core"; 8 import "dart:core";
9 import "dart:io"; 9 import "dart:io";
10 10
11 import 'android.dart'; 11 import 'android.dart';
12 import 'http_server.dart'; 12 import 'http_server.dart';
13 import 'utils.dart'; 13 import 'utils.dart';
14 14
15 class BrowserOutput { 15 class BrowserOutput {
16 final StringBuffer stdout = new StringBuffer(); 16 final StringBuffer stdout = new StringBuffer();
17 final StringBuffer stderr = new StringBuffer(); 17 final StringBuffer stderr = new StringBuffer();
(...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after
776 Timer timeoutTimer; 776 Timer timeoutTimer;
777 777
778 // Used for debugging, this is simply a unique identifier assigned to each 778 // Used for debugging, this is simply a unique identifier assigned to each
779 // test. 779 // test.
780 int id; 780 int id;
781 static int _idCounter = 0; 781 static int _idCounter = 0;
782 782
783 BrowserTest(this.url, this.doneCallback, this.timeout) { 783 BrowserTest(this.url, this.doneCallback, this.timeout) {
784 id = _idCounter++; 784 id = _idCounter++;
785 } 785 }
786
787 String toJSON() => JSON.encode({'url': url,
788 'id': id,
789 'isSimpleHtmlTest': false});
786 } 790 }
787 791
792
793 /**
794 * Describes a test with a custom HTML page to be run in the browser.
795 */
796 class HtmlTest extends BrowserTest {
797 List<String> expectedMessages;
798
799 HtmlTest(url, doneCallback, timeout, this.expectedMessages)
800 : super(url, doneCallback, timeout) { }
801
802 String toJSON() => JSON.encode({'url': url,
803 'id': id,
804 'isSimpleHtmlTest': true,
805 'expectedMessages': expectedMessages});
806 }
807
808
788 /* Describes the output of running the test in a browser */ 809 /* Describes the output of running the test in a browser */
789 class BrowserTestOutput { 810 class BrowserTestOutput {
790 final Duration delayUntilTestStarted; 811 final Duration delayUntilTestStarted;
791 final Duration duration; 812 final Duration duration;
792 813
793 final String lastKnownMessage; 814 final String lastKnownMessage;
794 815
795 final BrowserOutput browserOutput; 816 final BrowserOutput browserOutput;
796 final bool didTimeout; 817 final bool didTimeout;
797 818
(...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after
1295 errorReportingServer.listen(errorReportingHandler, onError: errorHandler); 1316 errorReportingServer.listen(errorReportingHandler, onError: errorHandler);
1296 } 1317 }
1297 1318
1298 void setupDispatchingServer(_) { 1319 void setupDispatchingServer(_) {
1299 DispatchingServer server = configuration['_servers_'].server; 1320 DispatchingServer server = configuration['_servers_'].server;
1300 void noCache(request) { 1321 void noCache(request) {
1301 request.response.headers.set("Cache-Control", 1322 request.response.headers.set("Cache-Control",
1302 "no-cache, no-store, must-revalidate"); 1323 "no-cache, no-store, must-revalidate");
1303 } 1324 }
1304 int testId(request) => 1325 int testId(request) =>
1305 int.parse(request.uri.queryParameters["id"].split("=")[1]); 1326 int.parse(request.uri.queryParameters["id"]);
1306 String browserId(request, prefix) => 1327 String browserId(request, prefix) =>
1307 request.uri.path.substring(prefix.length + 1); 1328 request.uri.path.substring(prefix.length + 1);
1308 1329
1309 1330
1310 server.addHandler(reportPath, (HttpRequest request) { 1331 server.addHandler(reportPath, (HttpRequest request) {
1311 noCache(request); 1332 noCache(request);
1312 handleReport(request, browserId(request, reportPath), 1333 handleReport(request, browserId(request, reportPath),
1313 testId(request), isStatusUpdate: false); 1334 testId(request), isStatusUpdate: false);
1314 }); 1335 });
1315 server.addHandler(statusUpdatePath, (HttpRequest request) { 1336 server.addHandler(statusUpdatePath, (HttpRequest request) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1378 testStartedCallBack(browserId, back, testId); 1399 testStartedCallBack(browserId, back, testId);
1379 }, onError: (error) { DebugLogger.error("$error"); }); 1400 }, onError: (error) { DebugLogger.error("$error"); });
1380 } 1401 }
1381 1402
1382 String getNextTest(String browserId) { 1403 String getNextTest(String browserId) {
1383 var nextTest = nextTestCallBack(browserId); 1404 var nextTest = nextTestCallBack(browserId);
1384 if (underTermination) { 1405 if (underTermination) {
1385 // Browsers will be killed shortly, send them a terminate signal so 1406 // Browsers will be killed shortly, send them a terminate signal so
1386 // that they stop pulling. 1407 // that they stop pulling.
1387 return terminateSignal; 1408 return terminateSignal;
1388 } else if (nextTest == null) {
1389 // We don't currently have any tests ready for consumption, wait.
1390 return waitSignal;
1391 } else { 1409 } else {
1392 return "${nextTest.url}#id=${nextTest.id}"; 1410 return nextTest == null ? waitSignal : nextTest.toJSON();
1393 } 1411 }
1394 } 1412 }
1395 1413
1396 String getDriverUrl(String browserId) { 1414 String getDriverUrl(String browserId) {
1397 if (errorReportingServer == null) { 1415 if (errorReportingServer == null) {
1398 print("Bad browser testing server, you are not started yet. Can't " 1416 print("Bad browser testing server, you are not started yet. Can't "
1399 "produce driver url"); 1417 "produce driver url");
1400 exit(1); 1418 exit(1);
1401 // This should never happen - exit immediately; 1419 // This should never happen - exit immediately;
1402 } 1420 }
1403 var port = configuration['_servers_'].port; 1421 var port = configuration['_servers_'].port;
1404 return "http://$localIp:$port/driver/$browserId"; 1422 return "http://$localIp:$port/driver/$browserId";
1405 } 1423 }
1406 1424
1407 1425
1408 String getDriverPage(String browserId) { 1426 String getDriverPage(String browserId) {
1409 var errorReportingUrl = 1427 var errorReportingUrl =
1410 "http://$localIp:${errorReportingServer.port}/$browserId"; 1428 "http://$localIp:${errorReportingServer.port}/$browserId";
1411 String driverContent = """ 1429 String driverContent = """
1412 <!DOCTYPE html><html> 1430 <!DOCTYPE html><html>
1413 <head> 1431 <head>
1414 <title>Driving page</title> 1432 <title>Driving page</title>
1415 <script type='text/javascript'> 1433 <script type='text/javascript'>
1434 var STATUS_UPDATE_INTERVAL = 10000;
1435
1416 function startTesting() { 1436 function startTesting() {
1417 var number_of_tests = 0; 1437 var number_of_tests = 0;
1418 var current_id; 1438 var current_id;
1419 var next_id; 1439 var next_id;
1420 // Describes a state where we are currently fetching the next test 1440 // Describes a state where we are currently fetching the next test
1421 // from the server. We use this to never double request tasks. 1441 // from the server. We use this to never double request tasks.
1422 var test_completed = true; 1442 var test_completed = true;
1423 var testing_window; 1443 var testing_window;
1424 1444
1425 var embedded_iframe = document.getElementById('embedded_iframe'); 1445 var embedded_iframe = document.getElementById('embedded_iframe');
1426 var number_div = document.getElementById('number'); 1446 var number_div = document.getElementById('number');
1427 var executing_div = document.getElementById('currently_executing'); 1447 var executing_div = document.getElementById('currently_executing');
1428 var error_div = document.getElementById('unhandled_error'); 1448 var error_div = document.getElementById('unhandled_error');
1429 var use_iframe = ${useIframe}; 1449 var use_iframe = ${useIframe};
1430 var start = new Date(); 1450 var start = new Date();
1431 1451
1452 // Object that holds the state of an HTML test
1453 var html_test;
1454
1432 function newTaskHandler() { 1455 function newTaskHandler() {
1433 if (this.readyState == this.DONE) { 1456 if (this.readyState == this.DONE) {
1434 if (this.status == 200) { 1457 if (this.status == 200) {
1435 if (this.responseText == '$waitSignal') { 1458 if (this.responseText == '$waitSignal') {
1436 setTimeout(getNextTask, 500); 1459 setTimeout(getNextTask, 500);
1437 } else if (this.responseText == '$terminateSignal') { 1460 } else if (this.responseText == '$terminateSignal') {
1438 // Don't do anything, we will be killed shortly. 1461 // Don't do anything, we will be killed shortly.
1439 } else { 1462 } else {
1440 var elapsed = new Date() - start; 1463 var elapsed = new Date() - start;
1441 // The task is send to us as: 1464 var nextTask = JSON.parse(this.responseText);
1442 // URL#ID 1465 var url = nextTask.url;
1443 var split = this.responseText.split('#'); 1466 next_id = nextTask.id;
1444 var nextTask = split[0]; 1467 if (nextTask.isHtmlTest) {
1445 next_id = split[1]; 1468 html_test = {
1446 run(nextTask); 1469 expected_messages: nextTask.expectedMessages,
1470 found_message_count: 0,
1471 double_received_messages: [],
1472 unexpected_messages: [],
1473 found_messages: {}
1474 };
1475 for (var i = 0; i < html_test.expected_messages.length; ++i) {
1476 html_test.found_messages[html_test.expected_messages[i]] = 0;
1477 }
1478 } else {
1479 html_test = null;
1480 }
1481 run(url);
1447 } 1482 }
1448 } else { 1483 } else {
1449 reportError('Could not contact the server and get a new task'); 1484 reportError('Could not contact the server and get a new task');
1450 } 1485 }
1451 } 1486 }
1452 } 1487 }
1453 1488
1454 function contactBrowserController(method, 1489 function contactBrowserController(method,
1455 path, 1490 path,
1456 callback, 1491 callback,
1457 msg, 1492 msg,
1458 isUrlEncoded) { 1493 isUrlEncoded) {
1459 var client = new XMLHttpRequest(); 1494 var client = new XMLHttpRequest();
1460 client.onreadystatechange = callback; 1495 client.onreadystatechange = callback;
1461 client.open(method, path); 1496 client.open(method, path);
1462 if (isUrlEncoded) { 1497 if (isUrlEncoded) {
1463 client.setRequestHeader('Content-type', 1498 client.setRequestHeader('Content-type',
1464 'application/x-www-form-urlencoded'); 1499 'application/x-www-form-urlencoded');
1465 } 1500 }
1466 client.send(msg); 1501 client.send(msg);
1467 } 1502 }
1468 1503
1469 function getNextTask() { 1504 function getNextTask() {
1470 // Until we have the next task we set the current_id to a specific 1505 // Until we have the next task we set the current_id to a specific
1471 // negative value. 1506 // negative value.
1472 contactBrowserController( 1507 contactBrowserController(
1473 'GET', '$nextTestPath/$browserId', newTaskHandler, "", false); 1508 'GET', '$nextTestPath/$browserId', newTaskHandler, "", false);
1474 } 1509 }
1475 1510
1511 function childError(message, filename, lineno, colno, error) {
1512 sendStatusUpdate();
1513 if (error) {
1514 reportMessage('FAIL:' + filename + ':' + lineno +
1515 ':' + colno + ':' + message + '\\n' + error.stack, false, false);
1516 } else if (filename) {
1517 reportMessage('FAIL:' + filename + ':' + lineno +
1518 ':' + colno + ':' + message, false, false);
1519 } else {
1520 reportMessage('FAIL: ' + message, false, false);
1521 }
1522 return true;
1523 }
1524
1525 function setChildHandlers(e) {
1526 embedded_iframe.contentWindow.addEventListener('message',
1527 childMessageHandler,
1528 false);
1529 embedded_iframe.contentWindow.onerror = childError;
1530 reportMessage("First message from html test", true, false);
1531 html_test.handlers_installed = true;
1532 sendRepeatingStatusUpdate();
1533 }
1534
1535 function checkChildHandlersInstalled() {
1536 if (!html_test.handlers_installed) {
1537 reportMessage("First message from html test", true, false);
1538 reportMessage(
1539 'FAIL: Html test did not call ' +
1540 'window.parent.dispatchEvent(new Event("detect_errors")) ' +
1541 'as its first action', false, false);
1542 }
1543 }
1544
1476 function run(url) { 1545 function run(url) {
1477 number_of_tests++; 1546 number_of_tests++;
1478 number_div.innerHTML = number_of_tests; 1547 number_div.innerHTML = number_of_tests;
1479 executing_div.innerHTML = url; 1548 executing_div.innerHTML = url;
1480 if (use_iframe) { 1549 if (use_iframe) {
1550 if (html_test) {
1551 window.addEventListener('detect_errors', setChildHandlers, false);
1552 embedded_iframe.onload = checkChildHandlersInstalled;
1553 } else {
1554 embedded_iframe.onload = null;
1555 }
1481 embedded_iframe.src = url; 1556 embedded_iframe.src = url;
1482 } else { 1557 } else {
1483 if (typeof testing_window != 'undefined') { 1558 if (typeof testing_window != 'undefined') {
1484 testing_window.close(); 1559 testing_window.close();
1485 } 1560 }
1486 testing_window = window.open(url); 1561 testing_window = window.open(url);
1487 } 1562 }
1488 } 1563 }
1489 1564
1490 window.onerror = function (message, url, lineNumber) { 1565 window.onerror = function (message, url, lineNumber) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1551 } 1626 }
1552 1627
1553 function parseResult(result) { 1628 function parseResult(result) {
1554 var parsedData = null; 1629 var parsedData = null;
1555 try { 1630 try {
1556 parsedData = JSON.parse(result); 1631 parsedData = JSON.parse(result);
1557 } catch(error) { } 1632 } catch(error) { }
1558 return parsedData; 1633 return parsedData;
1559 } 1634 }
1560 1635
1636 // Browser tests send JSON messages to the driver window, handled here.
1561 function messageHandler(e) { 1637 function messageHandler(e) {
1562 var msg = e.data; 1638 var msg = e.data;
1563 if (typeof msg != 'string') return; 1639 if (typeof msg != 'string') return;
1564 1640
1565 var parsedData = parseResult(msg); 1641 var parsedData = parseResult(msg);
1566 if (parsedData) { 1642 if (parsedData) {
1567 // Only if the JSON message contains all required parameters, 1643 // Only if the JSON message contains all required parameters,
1568 // will we handle it and post it back to the test controller. 1644 // will we handle it and post it back to the test controller.
1569 if ('message' in parsedData && 1645 if ('message' in parsedData &&
1570 'is_first_message' in parsedData && 1646 'is_first_message' in parsedData &&
1571 'is_status_update' in parsedData && 1647 'is_status_update' in parsedData &&
1572 'is_done' in parsedData) { 1648 'is_done' in parsedData) {
1573 var message = parsedData['message']; 1649 var message = parsedData['message'];
1574 var isFirstMessage = parsedData['is_first_message']; 1650 var isFirstMessage = parsedData['is_first_message'];
1575 var isStatusUpdate = parsedData['is_status_update']; 1651 var isStatusUpdate = parsedData['is_status_update'];
1576 var isDone = parsedData['is_done']; 1652 var isDone = parsedData['is_done'];
1577 if (!isFirstMessage && !isStatusUpdate) { 1653 if (!isFirstMessage && !isStatusUpdate) {
1578 if (!isDone) { 1654 if (!isDone) {
1579 alert("Bug in test_controller.js: " + 1655 alert("Bug in test_controller.js: " +
1580 "isFirstMessage/isStatusUpdate/isDone were all false"); 1656 "isFirstMessage/isStatusUpdate/isDone were all false");
1581 } 1657 }
1582 } 1658 }
1583 reportMessage(message, isFirstMessage, isStatusUpdate); 1659 reportMessage(message, isFirstMessage, isStatusUpdate);
1584 } 1660 }
1585 } 1661 }
1586 } 1662 }
1587 1663
1588 window.addEventListener('message', messageHandler, false); 1664 function sendStatusUpdate () {
1589 waitForDone = false; 1665 var dom =
1666 embedded_iframe.contentWindow.document.documentElement.innerHTML;
1667 reportMessage('Status:\\n Messages received multiple times:\\n ' +
1668 html_test.double_received_messages +
1669 '\\n Unexpected messages:\\n ' +
1670 html_test.unexpected_messages +
1671 '\\n DOM:\\n ' + dom, false, true);
1672 }
1590 1673
1674 function sendRepeatingStatusUpdate() {
1675 sendStatusUpdate();
1676 setTimeout(sendRepeatingStatusUpdate, STATUS_UPDATE_INTERVAL);
1677 }
1678
1679 // HTML tests post messages to their own window, handled by this handler.
1680 // This handler is installed on the child window when it sends the
1681 // 'detect_errors' event. Every HTML test must send 'detect_errors' to
1682 // its parent window as its first action, so all errors will be caught.
1683 function childMessageHandler(e) {
1684 var msg = e.data;
1685 if (typeof msg != 'string') return;
1686 if (msg in html_test.found_messages) {
1687 html_test.found_messages[msg]++;
1688 if (html_test.found_messages[msg] == 1) {
1689 html_test.found_message_count++;
1690 } else {
1691 html_test.double_received_messages.push(msg);
1692 sendStatusUpdate();
1693 }
1694 } else {
1695 html_test.unexpected_messages.push(msg);
1696 sendStatusUpdate();
1697 }
1698 if (html_test.found_message_count ==
1699 html_test.expected_messages.length) {
1700 reportMessage('Test done: PASS', false, false);
1701 }
1702 }
1703
1704 if (!html_test) {
1705 window.addEventListener('message', messageHandler, false);
1706 waitForDone = false;
1707 }
1591 getNextTask(); 1708 getNextTask();
1592 } 1709 }
1593
1594 </script> 1710 </script>
1595 </head> 1711 </head>
1596 <body onload="startTesting()"> 1712 <body onload="startTesting()">
1597 Dart test driver, number of tests: <div id="number"></div><br> 1713 Dart test driver, number of tests: <div id="number"></div><br>
1598 Currently executing: <div id="currently_executing"></div><br> 1714 Currently executing: <div id="currently_executing"></div><br>
1599 Unhandled error: <div id="unhandled_error"></div> 1715 Unhandled error: <div id="unhandled_error"></div>
1600 <iframe id="embedded_iframe"></iframe> 1716 <iframe id="embedded_iframe"></iframe>
1601 </body> 1717 </body>
1602 </html> 1718 </html>
1603 """; 1719 """;
1604 return driverContent; 1720 return driverContent;
1605 } 1721 }
1606 } 1722 }
OLDNEW
« no previous file with comments | « no previous file | tools/testing/dart/test_controller.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698