Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |