channelrequest_test.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.net.ChannelRequestTest');
  15. goog.setTestOnly('goog.net.ChannelRequestTest');
  16. goog.require('goog.Uri');
  17. goog.require('goog.functions');
  18. goog.require('goog.net.BrowserChannel');
  19. goog.require('goog.net.ChannelDebug');
  20. goog.require('goog.net.ChannelRequest');
  21. goog.require('goog.testing.MockClock');
  22. goog.require('goog.testing.PropertyReplacer');
  23. goog.require('goog.testing.jsunit');
  24. goog.require('goog.testing.net.XhrIo');
  25. goog.require('goog.testing.recordFunction');
  26. var channelRequest;
  27. var mockBrowserChannel;
  28. var mockClock;
  29. var stubs;
  30. var xhrIo;
  31. /**
  32. * Time to wait for a network request to time out, before aborting.
  33. */
  34. var WATCHDOG_TIME = 2000;
  35. /**
  36. * Time to throttle readystatechange events.
  37. */
  38. var THROTTLE_TIME = 500;
  39. /**
  40. * A really long time - used to make sure no more timeouts will fire.
  41. */
  42. var ALL_DAY_MS = 1000 * 60 * 60 * 24;
  43. function setUp() {
  44. mockClock = new goog.testing.MockClock();
  45. mockClock.install();
  46. stubs = new goog.testing.PropertyReplacer();
  47. }
  48. function tearDown() {
  49. stubs.reset();
  50. mockClock.uninstall();
  51. }
  52. /**
  53. * Constructs a duck-type BrowserChannel that tracks the completed requests.
  54. * @constructor
  55. */
  56. function MockBrowserChannel() {
  57. this.reachabilityEvents = {};
  58. this.isClosed = function() { return false; };
  59. this.isActive = function() { return true; };
  60. this.shouldUseSecondaryDomains = function() { return false; };
  61. this.completedRequests = [];
  62. this.notifyServerReachabilityEvent = function(reachabilityType) {
  63. if (!this.reachabilityEvents[reachabilityType]) {
  64. this.reachabilityEvents[reachabilityType] = 0;
  65. }
  66. this.reachabilityEvents[reachabilityType]++;
  67. };
  68. this.onRequestComplete = function(request) {
  69. this.completedRequests.push(request);
  70. };
  71. this.onRequestData = function(request, data) {};
  72. }
  73. /**
  74. * Creates a real ChannelRequest object, with some modifications for
  75. * testability:
  76. * <ul>
  77. * <li>The BrowserChannel is a MockBrowserChannel.
  78. * <li>The new watchdogTimeoutCallCount property tracks onWatchDogTimeout_()
  79. * calls.
  80. * <li>The timeout is set to WATCHDOG_TIME.
  81. * </ul>
  82. */
  83. function createChannelRequest() {
  84. xhrIo = new goog.testing.net.XhrIo();
  85. xhrIo.abort = xhrIo.abort || function() { this.active_ = false; };
  86. // Install mock browser channel and no-op debug logger.
  87. mockBrowserChannel = new MockBrowserChannel();
  88. channelRequest = new goog.net.ChannelRequest(
  89. mockBrowserChannel, new goog.net.ChannelDebug());
  90. // Install test XhrIo.
  91. mockBrowserChannel.createXhrIo = function() { return xhrIo; };
  92. // Install watchdogTimeoutCallCount.
  93. channelRequest.watchdogTimeoutCallCount = 0;
  94. channelRequest.originalOnWatchDogTimeout = channelRequest.onWatchDogTimeout_;
  95. channelRequest.onWatchDogTimeout_ = function() {
  96. this.watchdogTimeoutCallCount++;
  97. return this.originalOnWatchDogTimeout();
  98. };
  99. channelRequest.setTimeout(WATCHDOG_TIME);
  100. }
  101. /**
  102. * Run through the lifecycle of a long lived request, checking that the right
  103. * network events are reported.
  104. */
  105. function testNetworkEvents() {
  106. createChannelRequest();
  107. channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true);
  108. checkReachabilityEvents(1, 0, 0, 0);
  109. if (goog.net.ChannelRequest.supportsXhrStreaming()) {
  110. xhrIo.simulatePartialResponse('17\nI am a BC Message');
  111. checkReachabilityEvents(1, 0, 0, 1);
  112. xhrIo.simulatePartialResponse('23\nI am another BC Message');
  113. checkReachabilityEvents(1, 0, 0, 2);
  114. xhrIo.simulateResponse(200, '16\Final BC Message');
  115. checkReachabilityEvents(1, 1, 0, 2);
  116. } else {
  117. xhrIo.simulateResponse(200, '16\Final BC Message');
  118. checkReachabilityEvents(1, 1, 0, 0);
  119. }
  120. }
  121. /**
  122. * Test throttling of readystatechange events.
  123. */
  124. function testNetworkEvents_throttleReadyStateChange() {
  125. createChannelRequest();
  126. channelRequest.setReadyStateChangeThrottle(THROTTLE_TIME);
  127. var recordedHandler =
  128. goog.testing.recordFunction(channelRequest.xmlHttpHandler_);
  129. stubs.set(channelRequest, 'xmlHttpHandler_', recordedHandler);
  130. channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true);
  131. assertEquals(1, recordedHandler.getCallCount());
  132. checkReachabilityEvents(1, 0, 0, 0);
  133. if (goog.net.ChannelRequest.supportsXhrStreaming()) {
  134. xhrIo.simulatePartialResponse('17\nI am a BC Message');
  135. checkReachabilityEvents(1, 0, 0, 1);
  136. assertEquals(3, recordedHandler.getCallCount());
  137. // Second event should be throttled
  138. xhrIo.simulatePartialResponse('23\nI am another BC Message');
  139. assertEquals(3, recordedHandler.getCallCount());
  140. xhrIo.simulatePartialResponse('27\nI am yet another BC Message');
  141. assertEquals(3, recordedHandler.getCallCount());
  142. mockClock.tick(THROTTLE_TIME);
  143. checkReachabilityEvents(1, 0, 0, 3);
  144. // Only one more call because of throttling.
  145. assertEquals(4, recordedHandler.getCallCount());
  146. xhrIo.simulateResponse(200, '16\Final BC Message');
  147. checkReachabilityEvents(1, 1, 0, 3);
  148. assertEquals(5, recordedHandler.getCallCount());
  149. } else {
  150. xhrIo.simulateResponse(200, '16\Final BC Message');
  151. checkReachabilityEvents(1, 1, 0, 0);
  152. }
  153. }
  154. /**
  155. * Make sure that the request "completes" with an error when the timeout
  156. * expires.
  157. */
  158. function testRequestTimeout() {
  159. createChannelRequest();
  160. channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true);
  161. assertEquals(0, channelRequest.watchdogTimeoutCallCount);
  162. assertEquals(0, channelRequest.channel_.completedRequests.length);
  163. // Watchdog timeout.
  164. mockClock.tick(WATCHDOG_TIME);
  165. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  166. assertEquals(1, channelRequest.channel_.completedRequests.length);
  167. assertFalse(channelRequest.getSuccess());
  168. // Make sure no more timers are firing.
  169. mockClock.tick(ALL_DAY_MS);
  170. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  171. assertEquals(1, channelRequest.channel_.completedRequests.length);
  172. checkReachabilityEvents(1, 0, 1, 0);
  173. }
  174. function testRequestTimeoutWithUnexpectedException() {
  175. createChannelRequest();
  176. channelRequest.channel_.createXhrIo = goog.functions.error('Weird error');
  177. try {
  178. channelRequest.xmlHttpGet(new goog.Uri('some_uri'), true, null);
  179. fail('Expected error');
  180. } catch (e) {
  181. assertEquals('Weird error', e.message);
  182. }
  183. assertEquals(0, channelRequest.watchdogTimeoutCallCount);
  184. assertEquals(0, channelRequest.channel_.completedRequests.length);
  185. // Watchdog timeout.
  186. mockClock.tick(WATCHDOG_TIME);
  187. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  188. assertEquals(1, channelRequest.channel_.completedRequests.length);
  189. assertFalse(channelRequest.getSuccess());
  190. // Make sure no more timers are firing.
  191. mockClock.tick(ALL_DAY_MS);
  192. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  193. assertEquals(1, channelRequest.channel_.completedRequests.length);
  194. checkReachabilityEvents(0, 0, 1, 0);
  195. }
  196. function testActiveXBlocked() {
  197. createChannelRequest();
  198. stubs.set(
  199. goog.global, 'ActiveXObject', goog.functions.error('Active X blocked'));
  200. channelRequest.tridentGet(new goog.Uri('some_uri'), false);
  201. assertFalse(channelRequest.getSuccess());
  202. assertEquals(
  203. goog.net.ChannelRequest.Error.ACTIVE_X_BLOCKED,
  204. channelRequest.getLastError());
  205. checkReachabilityEvents(0, 0, 0, 0);
  206. }
  207. /**
  208. * This is a private method but we rely on it to avoid XSS, so it's important
  209. * to verify it works properly.
  210. */
  211. function testEscapeForStringInScript() {
  212. var actual = goog.net.ChannelRequest.escapeForStringInScript_('"\'<>');
  213. assertEquals('\\"\\\'\\x3c\\x3e', actual);
  214. }
  215. function checkReachabilityEvents(reqMade, reqSucceeded, reqFail, backChannel) {
  216. var Reachability = goog.net.BrowserChannel.ServerReachability;
  217. assertEquals(
  218. reqMade,
  219. mockBrowserChannel.reachabilityEvents[Reachability.REQUEST_MADE] || 0);
  220. assertEquals(
  221. reqSucceeded,
  222. mockBrowserChannel.reachabilityEvents[Reachability.REQUEST_SUCCEEDED] ||
  223. 0);
  224. assertEquals(
  225. reqFail,
  226. mockBrowserChannel.reachabilityEvents[Reachability.REQUEST_FAILED] || 0);
  227. assertEquals(
  228. backChannel,
  229. mockBrowserChannel
  230. .reachabilityEvents[Reachability.BACK_CHANNEL_ACTIVITY] ||
  231. 0);
  232. }