test_processasync.js
Go to the documentation of this file.
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et: */
3 /* ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is httpd.js code.
17  *
18  * The Initial Developer of the Original Code is
19  * the Mozilla Corporation.
20  * Portions created by the Initial Developer are Copyright (C) 2009
21  * the Initial Developer. All Rights Reserved.
22  *
23  * Contributor(s):
24  * Jeff Walden <jwalden+code@mit.edu>
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either the GNU General Public License Version 2 or later (the "GPL"), or
28  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39 
40 /*
41  * Tests for correct behavior of asynchronous responses.
42  */
43 
44 const PORT = 4444;
45 const PREPATH = "http://localhost:" + PORT;
46 
47 function run_test()
48 {
49  var srv = createServer();
50  for (var path in handlers)
51  srv.registerPathHandler(path, handlers[path]);
52  srv.start(PORT);
53 
55 }
56 
57 
58 /***************
59  * BEGIN TESTS *
60  ***************/
61 
62 var test;
63 var tests = [];
64 var handlers = {};
65 
66 function handleSync(request, response)
67 {
68  response.setStatusLine(request.httpVersion, 500, "handleSync fail");
69 
70  try
71  {
72  response.finish();
73  do_throw("finish called on sync response");
74  }
75  catch (e)
76  {
77  isException(e, Cr.NS_ERROR_UNEXPECTED);
78  }
79 
80  response.setStatusLine(request.httpVersion, 200, "handleSync pass");
81 }
82 handlers["/handleSync"] = handleSync;
83 
84 function start_handleSync(ch, cx)
85 {
86  do_check_eq(ch.responseStatus, 200);
87  do_check_eq(ch.responseStatusText, "handleSync pass");
88 }
89 
90 test = new Test(PREPATH + "/handleSync",
92 tests.push(test);
93 
94 
95 function handleAsync1(request, response)
96 {
97  response.setStatusLine(request.httpVersion, 500, "Old status line!");
98  response.setHeader("X-Foo", "old value", false);
99 
100  response.processAsync();
101 
102  response.setStatusLine(request.httpVersion, 200, "New status line!");
103  response.setHeader("X-Foo", "new value", false);
104 
105  response.finish();
106 
107  try
108  {
109  response.setStatusLine(request.httpVersion, 500, "Too late!");
110  do_throw("late setStatusLine didn't throw");
111  }
112  catch (e)
113  {
114  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
115  }
116 
117  try
118  {
119  response.setHeader("X-Foo", "late value", false);
120  do_throw("late setHeader didn't throw");
121  }
122  catch (e)
123  {
124  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
125  }
126 
127  try
128  {
129  response.bodyOutputStream;
130  do_throw("late bodyOutputStream get didn't throw");
131  }
132  catch (e)
133  {
134  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
135  }
136 
137  try
138  {
139  response.write("fugly");
140  do_throw("late write() didn't throw");
141  }
142  catch (e)
143  {
144  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
145  }
146 }
147 handlers["/handleAsync1"] = handleAsync1;
148 
149 function start_handleAsync1(ch, cx)
150 {
151  do_check_eq(ch.responseStatus, 200);
152  do_check_eq(ch.responseStatusText, "New status line!");
153  do_check_eq(ch.getResponseHeader("X-Foo"), "new value");
154 }
155 
156 function stop_handleAsync1(ch, cx, status, data)
157 {
158  do_check_eq(data.length, 0);
159 }
160 
161 test = new Test(PREPATH + "/handleAsync1",
163 tests.push(test);
164 
165 
166 const startToHeaderDelay = 500;
168 
169 function handleAsync2(request, response)
170 {
171  response.processAsync();
172 
173  response.setStatusLine(request.httpVersion, 200, "Status line");
174  response.setHeader("X-Custom-Header", "value", false);
175 
176  callLater(startToHeaderDelay, function()
177  {
178  var body = "BO";
179  response.bodyOutputStream.write(body, body.length);
180 
181  try
182  {
183  response.setStatusLine(request.httpVersion, 500, "after body write");
184  do_throw("setStatusLine succeeded");
185  }
186  catch (e)
187  {
188  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
189  }
190 
191  try
192  {
193  response.setHeader("X-Custom-Header", "new 1", false);
194  }
195  catch (e)
196  {
197  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
198  }
199 
201  {
202  var body = "DY";
203  response.bodyOutputStream.write(body, body.length);
204 
205  response.finish();
206  response.finish(); // idempotency
207 
208  try
209  {
210  response.setStatusLine(request.httpVersion, 500, "after finish");
211  }
212  catch (e)
213  {
214  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
215  }
216 
217  try
218  {
219  response.setHeader("X-Custom-Header", "new 2", false);
220  }
221  catch (e)
222  {
223  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
224  }
225 
226  try
227  {
228  response.write("EVIL");
229  }
230  catch (e)
231  {
232  isException(e, Cr.NS_ERROR_NOT_AVAILABLE);
233  }
234  });
235  });
236 }
237 handlers["/handleAsync2"] = handleAsync2;
238 
240 
241 function init_handleAsync2(ch)
242 {
243  var now = startTime_handleAsync2 = Date.now();
244  dumpn("*** init_HandleAsync2: start time " + now);
245 }
246 
247 function start_handleAsync2(ch, cx)
248 {
249  var now = Date.now();
250  dumpn("*** start_handleAsync2: onStartRequest time " + now + ", " +
251  (now - startTime_handleAsync2) + "ms after start time");
252  do_check_true(now >= startTime_handleAsync2 + startToHeaderDelay);
253 
254  do_check_eq(ch.responseStatus, 200);
255  do_check_eq(ch.responseStatusText, "Status line");
256  do_check_eq(ch.getResponseHeader("X-Custom-Header"), "value");
257 }
258 
259 function stop_handleAsync2(ch, cx, status, data)
260 {
261  var now = Date.now();
262  dumpn("*** stop_handleAsync2: onStopRequest time " + now + ", " +
263  (now - startTime_handleAsync2) + "ms after header time");
264  do_check_true(now >= startTime_handleAsync2 + startToFinishedDelay);
265 
266  do_check_eq(String.fromCharCode.apply(null, data), "BODY");
267 }
268 
269 test = new Test(PREPATH + "/handleAsync2",
271 tests.push(test);
272 
273 
274 const ASYNC_ERROR_BODY = "hi, I'm a body!";
275 
276 function handleAsyncError(request, response)
277 {
278  response.setStatusLine(request.httpVersion, 200, "Async Error");
279  response.setHeader("X-Foo", "header value", false);
280 
281  response.processAsync();
282 
283  response.write(ASYNC_ERROR_BODY, ASYNC_ERROR_BODY.length);
284 
285  // No turning back now -- except if there's an error!
286  throw "Monkey wrench!";
287 }
288 handlers["/handleAsyncError"] = handleAsyncError;
289 
290 function start_handleAsyncError(ch, cx)
291 {
292  do_check_eq(ch.responseStatus, 200);
293  do_check_eq(ch.responseStatusText, "Async Error");
294  do_check_eq(ch.getResponseHeader("X-Foo"), "header value");
295 }
296 
297 function stop_handleAsyncError(ch, cx, status, data)
298 {
299  // Lies! But not really!
300  do_check_true(ch.requestSucceeded);
301 
302  do_check_eq(data.length, ASYNC_ERROR_BODY.length);
303  do_check_eq(String.fromCharCode.apply(null, data), ASYNC_ERROR_BODY);
304 }
305 
306 test = new Test(PREPATH + "/handleAsyncError",
308 tests.push(test);
309 
310 
311 /*
312  * Tests that accessing output stream *before* calling processAsync() works
313  * correctly, sending written data immediately as it is written, not buffering
314  * until finish() is called -- which for this much data would mean we would all
315  * but certainly deadlock, since we're trying to read/write all this data in one
316  * process on a single thread.
317  */
318 function handleAsyncOrdering(request, response)
319 {
320  var out = new BinaryOutputStream(response.bodyOutputStream);
321 
322  var data = [];
323  for (var i = 0; i < 65536; i++)
324  data[i] = 0;
325  var count = 20;
326 
327  var writeData =
328  {
329  run: function()
330  {
331  if (count-- === 0)
332  {
333  response.finish();
334  return;
335  }
336 
337  try
338  {
339  out.writeByteArray(data, data.length);
340  step();
341  }
342  catch (e)
343  {
344  try
345  {
346  do_throw("error writing data: " + e);
347  }
348  finally
349  {
350  response.finish();
351  }
352  }
353  }
354  };
355  function step()
356  {
357  // Use gThreadManager here because it's expedient, *not* because it's
358  // intended for public use! If you do this in client code, expect me to
359  // knowingly break your code by changing the variable name. :-P
360  gThreadManager.currentThread
361  .dispatch(writeData, Ci.nsIThread.DISPATCH_NORMAL);
362  }
363  step();
364  response.processAsync();
365 }
366 handlers["/handleAsyncOrdering"] = handleAsyncOrdering;
367 
368 function stop_handleAsyncOrdering(ch, cx, status, data)
369 {
370  do_check_eq(data.length, 20 * 65536);
371  do_check_true(data.every(function(v) { return v === 0; }));
372 }
373 
374 test = new Test(PREPATH + "/handleAsyncOrdering",
376 tests.push(test);
377 
do_check_eq(typeof PlacesUtils,"object")
function stop_handleAsync1(ch, cx, status, data)
var tests
function handleAsyncOrdering(request, response)
function init_handleAsync2(ch)
function runHttpTests(testArray, done)
Definition: head_utils.js:340
var test
function handleAsyncError(request, response)
const BinaryOutputStream
Definition: httpd.js:213
function handleAsync2(request, response)
function stop_handleAsyncOrdering(ch, cx, status, data)
function dumpn(str)
Definition: httpd.js:172
function run_test()
function createServer()
Definition: head_utils.js:53
var count
Definition: test_bug7406.js:32
var handlers
function handleAsync1(request, response)
var gThreadManager
Definition: httpd.js:188
const PORT
const startToFinishedDelay
const PREPATH
const ASYNC_ERROR_BODY
return null
Definition: FeedWriter.js:1143
function start_handleAsync2(ch, cx)
const startToHeaderDelay
function testComplete(srv)
Definition: head_utils.js:292
function Test(path, initChannel, onStartRequest, onStopRequest)
Definition: head_utils.js:322
function start_handleSync(ch, cx)
const Cr
function stop_handleAsyncError(ch, cx, status, data)
var startTime_handleAsync2
const Ci
function now()
function handleSync(request, response)
observe data
Definition: FeedWriter.js:1329
function stop_handleAsync2(ch, cx, status, data)
function start_handleAsyncError(ch, cx)
_getSelectedPageStyle s i
function callLater(msecs, callback)
Definition: head_utils.js:237
function start_handleAsync1(ch, cx)
function isException(e, code)
Definition: head_utils.js:207
var srv