Chromium Code Reviews| Index: LayoutTests/http/tests/websocket/resources/close-common.js |
| diff --git a/LayoutTests/http/tests/websocket/resources/close-common.js b/LayoutTests/http/tests/websocket/resources/close-common.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5f7ba6fe7f44417d622b7bf207e93040d0ed2bd7 |
| --- /dev/null |
| +++ b/LayoutTests/http/tests/websocket/resources/close-common.js |
| @@ -0,0 +1,259 @@ |
| +// Variables used in js-test.js assertions. |
| +var exceptionName; |
| +var exceptionMessage; |
| +var exceptionProto; |
| +var closeEvent; |
| + |
| +// Constants. |
| +const invalidAccessErr = "InvalidAccessError"; |
| +const syntaxErr = "SyntaxError"; |
| +const normalClosure = 1000; |
| +const abnormalClosure = 1006; |
| +const url = "ws://127.0.0.1:8880/close"; |
| +const ws_handlers = ["onopen", "onerror", "onclose", "onmessage"]; |
| + |
| +// An explicit timeout is used so that we can capture the test output. |
| +var timeout; |
| + |
| +const badCodesTestCodes = [ |
| + 999, 1001, 2999, 5000, 65536 + 1000, 0x100000000 + 1000, 2999.9, NaN, "0", "100", 1/0, -1/0, 0/0, |
| +]; |
| + |
| +const badReasonTestReasons = [ |
| + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234", // 124 Byte |
| + "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012\u00a9", // length is 123, but 124 Byte in UTF-8 |
| +]; |
| + |
| +function createFailHandler(name, ws, reject) |
| +{ |
| + return function () { |
|
yhirano
2015/02/27 06:26:44
Please be consistent whether you put a space after
Adam Rice
2015/02/27 09:34:28
Originally this test used function () {...} style,
|
| + removeAllHandlers(ws); |
| + reject(name + " was called."); |
| + }; |
| +} |
| + |
| +function setDefaultHandlers(ws, reject) |
| +{ |
| + ws_handlers.forEach(function (handler) { |
| + ws[handler] = createFailHandler(handler, ws, reject); |
| + }); |
| +} |
| + |
| +// Ensure that the WebSocket can be garbage collected. |
| +function removeAllHandlers(ws) |
| +{ |
| + ws_handlers.forEach(function (handler) { |
| + ws[handler] = undefined; |
| + }); |
| +} |
| + |
| +// Verify that close() throws an exception when an invalid close code is passed. |
| +function badCodesTest() |
| +{ |
| + return new Promise(function (resolve, reject) { |
| + debug("badCodesTest: started"); |
| + var ws = new WebSocket(url); |
| + setDefaultHandlers(ws, reject); |
| + for (var id = 0; id < badCodesTestCodes.length; ++id) { |
|
yhirano
2015/02/27 06:26:44
[optional] You can use |for (var test_code of badC
Adam Rice
2015/02/27 09:34:28
I didn't know that worked yet. Thanks.
|
| + var test_code = badCodesTestCodes[id]; |
| + debug("badCodesTest: " + test_code); |
| + try { |
| + ws.close(test_code); |
| + reject("Exception not thrown for code " + test_code); |
| + return; |
| + } catch (e) { |
| + exceptionName = e.name; |
| + exceptionMessage = e.message; |
| + exceptionProto = Object.getPrototypeOf(e); |
| + shouldBeTrue("exceptionProto === DOMException.prototype"); |
| + shouldBeEqualToString("exceptionName", invalidAccessErr); |
| + var expectedCode = test_code; |
| + if (!expectedCode) |
| + expectedCode = 0; |
| + else if (expectedCode > 65535) |
| + expectedCode = 65535; |
| + else if (expectedCode < 0) |
| + expectedCode = 0; |
| + expectedCode = Math.floor(expectedCode); |
| + shouldBeEqualToString("exceptionMessage", "Failed to execute 'close' on 'WebSocket': The code must be either 1000, or between 3000 and 4999. " + expectedCode + " is neither."); |
| + } |
| + } |
| + removeAllHandlers(ws); |
| + resolve(); |
| + }); |
| +} |
| + |
| +// Verify that passing a valid code does not throw an exception. |
| +function goodCodeTest() |
| +{ |
| + return new Promise(function (resolve, reject) { |
| + debug("goodCodeTest: started"); |
| + var ws = new WebSocket(url); |
| + setDefaultHandlers(ws, reject); |
| + ws.onclose = function (e) |
| + { |
| + closeEvent = e; |
| + shouldBeEqualToNumber("closeEvent.code", abnormalClosure); |
| + resolve(); |
| + }; |
| + ws.onerror = function() |
| + { |
| + testPassed("onerror was called."); |
| + }; |
| + ws.close(1000.0); |
| + }); |
| +} |
| + |
| +// Verify that unpaired surrogates in the reason string are converted to U+FFFD |
| +// before sending to the remote server. |
| +function invalidUnicodeReasonTest() |
| +{ |
| + return new Promise(function (resolve, reject) { |
| + debug("invalidUnicodeReasonTest: started"); |
| + var ws = new WebSocket(url); |
|
yhirano
2015/02/27 06:26:44
+setDefaultHandlers
Adam Rice
2015/02/27 09:34:28
Done.
|
| + ws.onopen = function() { |
| + // 0xD834 is an unpaired surrogate. |
| + var invalidString = String.fromCharCode(0xD834); |
| + ws.close(1000, invalidString); |
| + }; |
| + ws.onclose = function(e) { |
| + closeEvent = e; |
| + shouldBeTrue("closeEvent.wasClean"); |
| + shouldBeEqualToString("closeEvent.reason", "\uFFFD"); |
| + resolve(); |
| + }; |
| + }); |
| +} |
| + |
| +// Verify that invalid reason strings passed to close() result in an exception |
| +// being thrown. |
| +function badReasonTest() |
| +{ |
| + return new Promise(function (resolve, reject) { |
| + debug("badReasonTest: started"); |
| + var ws = new WebSocket(url); |
| + setDefaultHandlers(ws, reject); |
| + for (var id = 0; id < badReasonTestReasons.length; ++id) { |
| + var test_reason = badReasonTestReasons[id]; |
| + debug("badReasonTest: " + test_reason); |
| + try { |
| + ws.close(normalClosure, test_reason); |
| + reject("Exception not thrown for bad reason " + test_reason); |
| + return; |
| + } catch (e) { |
| + exceptionName = e.name; |
| + exceptionProto = Object.getPrototypeOf(e); |
| + shouldBeTrue("exceptionProto === DOMException.prototype"); |
| + shouldBeEqualToString("exceptionName", syntaxErr); |
| + } |
| + } |
| + removeAllHandlers(ws); |
| + resolve(); |
| + }); |
| +} |
| + |
| +// Verify that a valid reason code passed to close() does not result in an |
| +// exception. |
| +function goodReasonTest() |
| +{ |
| + return new Promise(function (resolve, reject) { |
| + debug("goodReasonTest: started"); |
| + var ws = new WebSocket(url); |
|
yhirano
2015/02/27 06:26:44
+setDefaultHandlers
Adam Rice
2015/02/27 09:34:28
Done.
|
| + ws.onclose = function (e) |
| + { |
| + closeEvent = e; |
| + shouldBeEqualToNumber("closeEvent.code", abnormalClosure); |
| + resolve(); |
| + }; |
| + ws.onerror = function() |
| + { |
| + testPassed("onerror was called."); |
| + }; |
| + // 123 byte reason should not throw. |
| + ws.close(normalClosure, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123"); |
| + }); |
| +} |
| + |
| +// Verify that valid close codes and reasons are correctly send to the |
| +// WebSocket server. |
| +function codeAndReasonTest() |
| +{ |
| + const codes = [ |
| + 1000, |
| + 3000, |
| + 4000, |
| + 4999 |
| + ]; |
| + const reasons = [ |
| + "OK, Bye!", |
| + "3000", |
| + "code is 4000", |
| + "\u00a9 Google" |
| + ]; |
| + return new Promise(function(resolve, reject) { |
| + debug("codeAndReasonTest: started"); |
| + // Tests are run in series to produce deterministic output. |
| + var promise = Promise.resolve(); |
| + for (var id = 0; id < codes.length; ++id) { |
| + promise = promise.then(codeAndReasonSingleCase(codes[id], reasons[id])); |
| + } |
| + promise.then(resolve); |
| + }); |
| +} |
| + |
| +// (Return a function which returns a Promise to) handle a single code/reason |
| +// pair for the codeAndReasonTest. |
| +function codeAndReasonSingleCase(test_code, test_reason) { |
| + return function() { |
| + return new Promise(function (resolve, reject) { |
| + debug("codeAndReasonTest: " + test_code + ", '" + test_reason + "'"); |
| + var ws = new WebSocket(url); |
| + setDefaultHandlers(ws, reject); |
| + ws.onopen = function () |
| + { |
| + ws.close(test_code, test_reason); |
| + }; |
| + ws.onclose = function (e) |
| + { |
| + closeEvent = e; |
| + shouldBeTrue("closeEvent.wasClean"); |
| + shouldBeEqualToNumber("closeEvent.code", test_code); |
| + shouldBeEqualToString("closeEvent.reason", test_reason); |
| + resolve(); |
| + }; |
| + }); |
| + }; |
| +} |
| + |
| +function cleanup() { |
| + clearTimeout(timeout); |
| + finishJSTest(); |
| +} |
| + |
| +function onTimeout() { |
| + handleRejection("Timeout"); |
| +} |
| + |
| +function handleRejection(reason) { |
| + if (reason instanceof Error) { |
| + // Get a stack trace if an exception fired. |
| + testFailed(reason.stack); |
| + } else { |
| + testFailed(reason); |
| + } |
| + cleanup(); |
| +} |
| + |
| +function testClose() { |
| + // Set an explicit timeout in order to keep text output on failure. |
| + timeout = setTimeout(onTimeout, 5000); |
| + // Tests are run in series to produce deterministic output. |
| + badCodesTest() |
| + .then(goodCodeTest) |
| + .then(invalidUnicodeReasonTest) |
| + .then(badReasonTest) |
| + .then(goodReasonTest) |
| + .then(codeAndReasonTest) |
| + .then(cleanup) |
| + .catch(handleRejection); |
| +} |