| 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..00fa3bff586a1bf7268b10e7aacefbf1acd1a8cb
|
| --- /dev/null
|
| +++ b/LayoutTests/http/tests/websocket/resources/close-common.js
|
| @@ -0,0 +1,258 @@
|
| +// 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() {
|
| + 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 test_code of badCodesTestCodes) {
|
| + 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);
|
| + setDefaultHandlers(ws, reject);
|
| + 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 test_reason of badReasonTestReasons) {
|
| + 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);
|
| + setDefaultHandlers(ws, reject);
|
| + 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);
|
| +}
|
|
|