channelrequest_test.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright 2013 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. /**
  15. * @fileoverview Unit tests for goog.labs.net.webChannel.ChannelRequest.
  16. *
  17. */
  18. goog.provide('goog.labs.net.webChannel.channelRequestTest');
  19. goog.require('goog.Uri');
  20. goog.require('goog.functions');
  21. goog.require('goog.labs.net.webChannel.ChannelRequest');
  22. goog.require('goog.labs.net.webChannel.WebChannelDebug');
  23. goog.require('goog.labs.net.webChannel.requestStats');
  24. goog.require('goog.labs.net.webChannel.requestStats.ServerReachability');
  25. goog.require('goog.testing.MockClock');
  26. goog.require('goog.testing.PropertyReplacer');
  27. goog.require('goog.testing.jsunit');
  28. goog.require('goog.testing.net.XhrIo');
  29. goog.require('goog.testing.recordFunction');
  30. goog.setTestOnly('goog.labs.net.webChannel.channelRequestTest');
  31. var channelRequest;
  32. var mockChannel;
  33. var mockClock;
  34. var stubs;
  35. var xhrIo;
  36. var reachabilityEvents;
  37. /**
  38. * Time to wait for a network request to time out, before aborting.
  39. */
  40. var WATCHDOG_TIME = 2000;
  41. /**
  42. * Time to throttle readystatechange events.
  43. */
  44. var THROTTLE_TIME = 500;
  45. /**
  46. * A really long time - used to make sure no more timeouts will fire.
  47. */
  48. var ALL_DAY_MS = 1000 * 60 * 60 * 24;
  49. function shouldRunTests() {
  50. return goog.labs.net.webChannel.ChannelRequest.supportsXhrStreaming();
  51. }
  52. function setUp() {
  53. mockClock = new goog.testing.MockClock();
  54. mockClock.install();
  55. reachabilityEvents = {};
  56. stubs = new goog.testing.PropertyReplacer();
  57. // Mock out the stat notification code.
  58. var notifyServerReachabilityEvent = function(reachabilityType) {
  59. if (!reachabilityEvents[reachabilityType]) {
  60. reachabilityEvents[reachabilityType] = 0;
  61. }
  62. reachabilityEvents[reachabilityType]++;
  63. };
  64. stubs.set(
  65. goog.labs.net.webChannel.requestStats, 'notifyServerReachabilityEvent',
  66. notifyServerReachabilityEvent);
  67. }
  68. function tearDown() {
  69. stubs.reset();
  70. mockClock.uninstall();
  71. }
  72. /**
  73. * Constructs a duck-type WebChannelBase that tracks the completed requests.
  74. * @constructor
  75. * @struct
  76. * @final
  77. */
  78. function MockWebChannelBase() {
  79. this.isClosed = function() { return false; };
  80. this.isActive = function() { return true; };
  81. this.shouldUseSecondaryDomains = function() { return false; };
  82. this.completedRequests = [];
  83. this.onRequestComplete = function(request) {
  84. this.completedRequests.push(request);
  85. };
  86. this.onRequestData = function(request, data) {};
  87. }
  88. /**
  89. * Creates a real ChannelRequest object, with some modifications for
  90. * testability:
  91. * <ul>
  92. * <li>The channel is a mock channel.
  93. * <li>The new watchdogTimeoutCallCount property tracks onWatchDogTimeout_()
  94. * calls.
  95. * <li>The timeout is set to WATCHDOG_TIME.
  96. * </ul>
  97. */
  98. function createChannelRequest() {
  99. xhrIo = new goog.testing.net.XhrIo();
  100. xhrIo.abort = xhrIo.abort || function() { this.active_ = false; };
  101. // Install mock channel and no-op debug logger.
  102. mockChannel = new MockWebChannelBase();
  103. channelRequest = new goog.labs.net.webChannel.ChannelRequest(
  104. mockChannel, new goog.labs.net.webChannel.WebChannelDebug());
  105. // Install test XhrIo.
  106. mockChannel.createXhrIo = function() { return xhrIo; };
  107. // Install watchdogTimeoutCallCount.
  108. channelRequest.watchdogTimeoutCallCount = 0;
  109. channelRequest.originalOnWatchDogTimeout = channelRequest.onWatchDogTimeout_;
  110. channelRequest.onWatchDogTimeout_ = function() {
  111. channelRequest.watchdogTimeoutCallCount++;
  112. return channelRequest.originalOnWatchDogTimeout();
  113. };
  114. channelRequest.setTimeout(WATCHDOG_TIME);
  115. }
  116. /**
  117. * Run through the lifecycle of a long lived request, checking that the right
  118. * network events are reported.
  119. */
  120. function testNetworkEvents() {
  121. createChannelRequest();
  122. channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true);
  123. checkReachabilityEvents(1, 0, 0, 0);
  124. if (goog.labs.net.webChannel.ChannelRequest.supportsXhrStreaming()) {
  125. xhrIo.simulatePartialResponse('17\nI am a BC Message');
  126. checkReachabilityEvents(1, 0, 0, 1);
  127. xhrIo.simulatePartialResponse('23\nI am another BC Message');
  128. checkReachabilityEvents(1, 0, 0, 2);
  129. xhrIo.simulateResponse(200, '16\Final BC Message');
  130. checkReachabilityEvents(1, 1, 0, 2);
  131. } else {
  132. xhrIo.simulateResponse(200, '16\Final BC Message');
  133. checkReachabilityEvents(1, 1, 0, 0);
  134. }
  135. }
  136. /**
  137. * Test throttling of readystatechange events.
  138. */
  139. function testNetworkEvents_throttleReadyStateChange() {
  140. createChannelRequest();
  141. channelRequest.setReadyStateChangeThrottle(THROTTLE_TIME);
  142. var recordedHandler =
  143. goog.testing.recordFunction(channelRequest.xmlHttpHandler_);
  144. stubs.set(channelRequest, 'xmlHttpHandler_', recordedHandler);
  145. channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true);
  146. assertEquals(1, recordedHandler.getCallCount());
  147. checkReachabilityEvents(1, 0, 0, 0);
  148. if (goog.labs.net.webChannel.ChannelRequest.supportsXhrStreaming()) {
  149. xhrIo.simulatePartialResponse('17\nI am a BC Message');
  150. checkReachabilityEvents(1, 0, 0, 1);
  151. assertEquals(3, recordedHandler.getCallCount());
  152. // Second event should be throttled
  153. xhrIo.simulatePartialResponse('23\nI am another BC Message');
  154. assertEquals(3, recordedHandler.getCallCount());
  155. xhrIo.simulatePartialResponse('27\nI am yet another BC Message');
  156. assertEquals(3, recordedHandler.getCallCount());
  157. mockClock.tick(THROTTLE_TIME);
  158. checkReachabilityEvents(1, 0, 0, 3);
  159. // Only one more call because of throttling.
  160. assertEquals(4, recordedHandler.getCallCount());
  161. xhrIo.simulateResponse(200, '16\Final BC Message');
  162. checkReachabilityEvents(1, 1, 0, 3);
  163. assertEquals(5, recordedHandler.getCallCount());
  164. } else {
  165. xhrIo.simulateResponse(200, '16\Final BC Message');
  166. checkReachabilityEvents(1, 1, 0, 0);
  167. }
  168. }
  169. /**
  170. * Make sure that the request "completes" with an error when the timeout
  171. * expires.
  172. */
  173. function testRequestTimeout() {
  174. createChannelRequest();
  175. channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true);
  176. assertEquals(0, channelRequest.watchdogTimeoutCallCount);
  177. assertEquals(0, channelRequest.channel_.completedRequests.length);
  178. // Watchdog timeout.
  179. mockClock.tick(WATCHDOG_TIME);
  180. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  181. assertEquals(1, channelRequest.channel_.completedRequests.length);
  182. assertFalse(channelRequest.getSuccess());
  183. // Make sure no more timers are firing.
  184. mockClock.tick(ALL_DAY_MS);
  185. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  186. assertEquals(1, channelRequest.channel_.completedRequests.length);
  187. checkReachabilityEvents(1, 0, 1, 0);
  188. }
  189. function testRequestTimeoutWithUnexpectedException() {
  190. createChannelRequest();
  191. channelRequest.channel_.createXhrIo = goog.functions.error('Weird error');
  192. try {
  193. channelRequest.xmlHttpGet(new goog.Uri('some_uri'), true, null);
  194. fail('Expected error');
  195. } catch (e) {
  196. assertEquals('Weird error', e.message);
  197. }
  198. assertEquals(0, channelRequest.watchdogTimeoutCallCount);
  199. assertEquals(0, channelRequest.channel_.completedRequests.length);
  200. // Watchdog timeout.
  201. mockClock.tick(WATCHDOG_TIME);
  202. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  203. assertEquals(1, channelRequest.channel_.completedRequests.length);
  204. assertFalse(channelRequest.getSuccess());
  205. // Make sure no more timers are firing.
  206. mockClock.tick(ALL_DAY_MS);
  207. assertEquals(1, channelRequest.watchdogTimeoutCallCount);
  208. assertEquals(1, channelRequest.channel_.completedRequests.length);
  209. checkReachabilityEvents(0, 0, 1, 0);
  210. }
  211. function checkReachabilityEvents(reqMade, reqSucceeded, reqFail, backChannel) {
  212. var Reachability = goog.labs.net.webChannel.requestStats.ServerReachability;
  213. assertEquals(reqMade, reachabilityEvents[Reachability.REQUEST_MADE] || 0);
  214. assertEquals(
  215. reqSucceeded, reachabilityEvents[Reachability.REQUEST_SUCCEEDED] || 0);
  216. assertEquals(reqFail, reachabilityEvents[Reachability.REQUEST_FAILED] || 0);
  217. assertEquals(
  218. backChannel, reachabilityEvents[Reachability.BACK_CHANNEL_ACTIVITY] || 0);
  219. }