OLD | NEW |
(Empty) | |
| 1 // Variables used in js-test.js assertions. |
| 2 var exceptionName; |
| 3 var exceptionMessage; |
| 4 var exceptionProto; |
| 5 var closeEvent; |
| 6 |
| 7 // Constants. |
| 8 const invalidAccessErr = "InvalidAccessError"; |
| 9 const syntaxErr = "SyntaxError"; |
| 10 const normalClosure = 1000; |
| 11 const abnormalClosure = 1006; |
| 12 const url = "ws://127.0.0.1:8880/close"; |
| 13 const ws_handlers = ["onopen", "onerror", "onclose", "onmessage"]; |
| 14 |
| 15 // An explicit timeout is used so that we can capture the test output. |
| 16 var timeout; |
| 17 |
| 18 const badCodesTestCodes = [ |
| 19 999, 1001, 2999, 5000, 65536 + 1000, 0x100000000 + 1000, 2999.9, NaN, "0", "
100", 1/0, -1/0, 0/0, |
| 20 ]; |
| 21 |
| 22 const badReasonTestReasons = [ |
| 23 "123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234", // 124 Byte |
| 24 "123456789012345678901234567890123456789012345678901234567890123456789012345
67890123456789012345678901234567890123456789012\u00a9", // length is 123, but 12
4 Byte in UTF-8 |
| 25 ]; |
| 26 |
| 27 function createFailHandler(name, ws, reject) |
| 28 { |
| 29 return function() { |
| 30 removeAllHandlers(ws); |
| 31 reject(name + " was called."); |
| 32 }; |
| 33 } |
| 34 |
| 35 function setDefaultHandlers(ws, reject) |
| 36 { |
| 37 ws_handlers.forEach(function(handler) { |
| 38 ws[handler] = createFailHandler(handler, ws, reject); |
| 39 }); |
| 40 } |
| 41 |
| 42 // Ensure that the WebSocket can be garbage collected. |
| 43 function removeAllHandlers(ws) |
| 44 { |
| 45 ws_handlers.forEach(function(handler) { |
| 46 ws[handler] = undefined; |
| 47 }); |
| 48 } |
| 49 |
| 50 // Verify that close() throws an exception when an invalid close code is passed. |
| 51 function badCodesTest() |
| 52 { |
| 53 return new Promise(function(resolve, reject) { |
| 54 debug("badCodesTest: started"); |
| 55 var ws = new WebSocket(url); |
| 56 setDefaultHandlers(ws, reject); |
| 57 for (var test_code of badCodesTestCodes) { |
| 58 debug("badCodesTest: " + test_code); |
| 59 try { |
| 60 ws.close(test_code); |
| 61 reject("Exception not thrown for code " + test_code); |
| 62 return; |
| 63 } catch (e) { |
| 64 exceptionName = e.name; |
| 65 exceptionMessage = e.message; |
| 66 exceptionProto = Object.getPrototypeOf(e); |
| 67 shouldBeTrue("exceptionProto === DOMException.prototype"); |
| 68 shouldBeEqualToString("exceptionName", invalidAccessErr); |
| 69 var expectedCode = test_code; |
| 70 if (!expectedCode) |
| 71 expectedCode = 0; |
| 72 else if (expectedCode > 65535) |
| 73 expectedCode = 65535; |
| 74 else if (expectedCode < 0) |
| 75 expectedCode = 0; |
| 76 expectedCode = Math.floor(expectedCode); |
| 77 shouldBeEqualToString("exceptionMessage", "Failed to execute 'cl
ose' on 'WebSocket': The code must be either 1000, or between 3000 and 4999. " +
expectedCode + " is neither."); |
| 78 } |
| 79 } |
| 80 removeAllHandlers(ws); |
| 81 resolve(); |
| 82 }); |
| 83 } |
| 84 |
| 85 // Verify that passing a valid code does not throw an exception. |
| 86 function goodCodeTest() |
| 87 { |
| 88 return new Promise(function(resolve, reject) { |
| 89 debug("goodCodeTest: started"); |
| 90 var ws = new WebSocket(url); |
| 91 setDefaultHandlers(ws, reject); |
| 92 ws.onclose = function(e) { |
| 93 closeEvent = e; |
| 94 shouldBeEqualToNumber("closeEvent.code", abnormalClosure); |
| 95 resolve(); |
| 96 }; |
| 97 ws.onerror = function() { |
| 98 testPassed("onerror was called."); |
| 99 }; |
| 100 ws.close(1000.0); |
| 101 }); |
| 102 } |
| 103 |
| 104 // Verify that unpaired surrogates in the reason string are converted to U+FFFD |
| 105 // before sending to the remote server. |
| 106 function invalidUnicodeReasonTest() |
| 107 { |
| 108 return new Promise(function(resolve, reject) { |
| 109 debug("invalidUnicodeReasonTest: started"); |
| 110 var ws = new WebSocket(url); |
| 111 setDefaultHandlers(ws, reject); |
| 112 ws.onopen = function() { |
| 113 // 0xD834 is an unpaired surrogate. |
| 114 var invalidString = String.fromCharCode(0xD834); |
| 115 ws.close(1000, invalidString); |
| 116 }; |
| 117 ws.onclose = function(e) { |
| 118 closeEvent = e; |
| 119 shouldBeTrue("closeEvent.wasClean"); |
| 120 shouldBeEqualToString("closeEvent.reason", "\uFFFD"); |
| 121 resolve(); |
| 122 }; |
| 123 }); |
| 124 } |
| 125 |
| 126 // Verify that invalid reason strings passed to close() result in an exception |
| 127 // being thrown. |
| 128 function badReasonTest() |
| 129 { |
| 130 return new Promise(function(resolve, reject) { |
| 131 debug("badReasonTest: started"); |
| 132 var ws = new WebSocket(url); |
| 133 setDefaultHandlers(ws, reject); |
| 134 for (var test_reason of badReasonTestReasons) { |
| 135 debug("badReasonTest: " + test_reason); |
| 136 try { |
| 137 ws.close(normalClosure, test_reason); |
| 138 reject("Exception not thrown for bad reason " + test_reason); |
| 139 return; |
| 140 } catch (e) { |
| 141 exceptionName = e.name; |
| 142 exceptionProto = Object.getPrototypeOf(e); |
| 143 shouldBeTrue("exceptionProto === DOMException.prototype"); |
| 144 shouldBeEqualToString("exceptionName", syntaxErr); |
| 145 } |
| 146 } |
| 147 removeAllHandlers(ws); |
| 148 resolve(); |
| 149 }); |
| 150 } |
| 151 |
| 152 // Verify that a valid reason code passed to close() does not result in an |
| 153 // exception. |
| 154 function goodReasonTest() |
| 155 { |
| 156 return new Promise(function(resolve, reject) { |
| 157 debug("goodReasonTest: started"); |
| 158 var ws = new WebSocket(url); |
| 159 setDefaultHandlers(ws, reject); |
| 160 ws.onclose = function(e) { |
| 161 closeEvent = e; |
| 162 shouldBeEqualToNumber("closeEvent.code", abnormalClosure); |
| 163 resolve(); |
| 164 }; |
| 165 ws.onerror = function() { |
| 166 testPassed("onerror was called."); |
| 167 }; |
| 168 // 123 byte reason should not throw. |
| 169 ws.close(normalClosure, "12345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123"); |
| 170 }); |
| 171 } |
| 172 |
| 173 // Verify that valid close codes and reasons are correctly send to the |
| 174 // WebSocket server. |
| 175 function codeAndReasonTest() |
| 176 { |
| 177 const codes = [ |
| 178 1000, |
| 179 3000, |
| 180 4000, |
| 181 4999 |
| 182 ]; |
| 183 const reasons = [ |
| 184 "OK, Bye!", |
| 185 "3000", |
| 186 "code is 4000", |
| 187 "\u00a9 Google" |
| 188 ]; |
| 189 return new Promise(function(resolve, reject) { |
| 190 debug("codeAndReasonTest: started"); |
| 191 // Tests are run in series to produce deterministic output. |
| 192 var promise = Promise.resolve(); |
| 193 for (var id = 0; id < codes.length; ++id) { |
| 194 promise = promise.then(codeAndReasonSingleCase(codes[id], reasons[id
])); |
| 195 } |
| 196 promise.then(resolve); |
| 197 }); |
| 198 } |
| 199 |
| 200 // (Return a function which returns a Promise to) handle a single code/reason |
| 201 // pair for the codeAndReasonTest. |
| 202 function codeAndReasonSingleCase(test_code, test_reason) |
| 203 { |
| 204 return function() { |
| 205 return new Promise(function(resolve, reject) { |
| 206 debug("codeAndReasonTest: " + test_code + ", '" + test_reason + "'")
; |
| 207 var ws = new WebSocket(url); |
| 208 setDefaultHandlers(ws, reject); |
| 209 ws.onopen = function() { |
| 210 ws.close(test_code, test_reason); |
| 211 }; |
| 212 ws.onclose = function(e) { |
| 213 closeEvent = e; |
| 214 shouldBeTrue("closeEvent.wasClean"); |
| 215 shouldBeEqualToNumber("closeEvent.code", test_code); |
| 216 shouldBeEqualToString("closeEvent.reason", test_reason); |
| 217 resolve(); |
| 218 }; |
| 219 }); |
| 220 }; |
| 221 } |
| 222 |
| 223 function cleanup() |
| 224 { |
| 225 clearTimeout(timeout); |
| 226 finishJSTest(); |
| 227 } |
| 228 |
| 229 function onTimeout() |
| 230 { |
| 231 handleRejection("Timeout"); |
| 232 } |
| 233 |
| 234 function handleRejection(reason) |
| 235 { |
| 236 if (reason instanceof Error) { |
| 237 // Get a stack trace if an exception fired. |
| 238 testFailed(reason.stack); |
| 239 } else { |
| 240 testFailed(reason); |
| 241 } |
| 242 cleanup(); |
| 243 } |
| 244 |
| 245 function testClose() |
| 246 { |
| 247 // Set an explicit timeout in order to keep text output on failure. |
| 248 timeout = setTimeout(onTimeout, 5000); |
| 249 // Tests are run in series to produce deterministic output. |
| 250 badCodesTest() |
| 251 .then(goodCodeTest) |
| 252 .then(invalidUnicodeReasonTest) |
| 253 .then(badReasonTest) |
| 254 .then(goodReasonTest) |
| 255 .then(codeAndReasonTest) |
| 256 .then(cleanup) |
| 257 .catch(handleRejection); |
| 258 } |
OLD | NEW |