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

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

Powered by Google App Engine
This is Rietveld 408576698