webchannelbase_test.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  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.WebChannelBase.
  16. * @suppress {accessControls} Private methods are accessed for test purposes.
  17. *
  18. */
  19. goog.provide('goog.labs.net.webChannel.webChannelBaseTest');
  20. goog.require('goog.Timer');
  21. goog.require('goog.array');
  22. goog.require('goog.dom');
  23. goog.require('goog.functions');
  24. goog.require('goog.json');
  25. goog.require('goog.labs.net.webChannel.ChannelRequest');
  26. goog.require('goog.labs.net.webChannel.ForwardChannelRequestPool');
  27. goog.require('goog.labs.net.webChannel.WebChannelBase');
  28. goog.require('goog.labs.net.webChannel.WebChannelBaseTransport');
  29. goog.require('goog.labs.net.webChannel.WebChannelDebug');
  30. goog.require('goog.labs.net.webChannel.Wire');
  31. goog.require('goog.labs.net.webChannel.netUtils');
  32. goog.require('goog.labs.net.webChannel.requestStats');
  33. goog.require('goog.labs.net.webChannel.requestStats.Stat');
  34. goog.require('goog.structs.Map');
  35. goog.require('goog.testing.MockClock');
  36. goog.require('goog.testing.PropertyReplacer');
  37. goog.require('goog.testing.asserts');
  38. goog.require('goog.testing.jsunit');
  39. goog.setTestOnly('goog.labs.net.webChannel.webChannelBaseTest');
  40. /**
  41. * Delay between a network failure and the next network request.
  42. */
  43. var RETRY_TIME = 1000;
  44. /**
  45. * A really long time - used to make sure no more timeouts will fire.
  46. */
  47. var ALL_DAY_MS = 1000 * 60 * 60 * 24;
  48. var stubs = new goog.testing.PropertyReplacer();
  49. var channel;
  50. var deliveredMaps;
  51. var handler;
  52. var mockClock;
  53. var gotError;
  54. var numStatEvents;
  55. var lastStatEvent;
  56. var numTimingEvents;
  57. var lastPostSize;
  58. var lastPostRtt;
  59. var lastPostRetryCount;
  60. // Set to true to see the channel debug output in the browser window.
  61. var debug = false;
  62. // Debug message to print out when debug is true.
  63. var debugMessage = '';
  64. function debugToWindow(message) {
  65. if (debug) {
  66. debugMessage += message + '<br>';
  67. goog.dom.getElement('debug').innerHTML = debugMessage;
  68. }
  69. }
  70. /**
  71. * Stubs goog.labs.net.webChannel.netUtils to always time out. It maintains the
  72. * contract given by goog.labs.net.webChannel.netUtils.testNetwork, but always
  73. * times out (calling callback(false)).
  74. *
  75. * stubNetUtils should be called in tests that require it before
  76. * a call to testNetwork happens. It is reset at tearDown.
  77. */
  78. function stubNetUtils() {
  79. stubs.set(
  80. goog.labs.net.webChannel.netUtils, 'testLoadImage',
  81. function(url, timeout, callback) {
  82. goog.Timer.callOnce(goog.partial(callback, false), timeout);
  83. });
  84. }
  85. /**
  86. * Stubs goog.labs.net.webChannel.ForwardChannelRequestPool.isSpdyEnabled_
  87. * to manage the max pool size for the forward channel.
  88. *
  89. * @param {boolean} spdyEnabled Whether SPDY is enabled for the test.
  90. */
  91. function stubSpdyCheck(spdyEnabled) {
  92. stubs.set(
  93. goog.labs.net.webChannel.ForwardChannelRequestPool, 'isSpdyEnabled_',
  94. function() { return spdyEnabled; });
  95. }
  96. /**
  97. * Mock ChannelRequest.
  98. * @constructor
  99. * @struct
  100. * @final
  101. */
  102. var MockChannelRequest = function(
  103. channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) {
  104. this.channel_ = channel;
  105. this.channelDebug_ = channelDebug;
  106. this.sessionId_ = opt_sessionId;
  107. this.requestId_ = opt_requestId;
  108. this.successful_ = true;
  109. this.lastError_ = null;
  110. this.lastStatusCode_ = 200;
  111. // For debugging, keep track of whether this is a back or forward channel.
  112. this.isBack = !!(opt_requestId == 'rpc');
  113. this.isForward = !this.isBack;
  114. };
  115. MockChannelRequest.prototype.postData_ = null;
  116. MockChannelRequest.prototype.requestStartTime_ = null;
  117. MockChannelRequest.prototype.setExtraHeaders = function(extraHeaders) {};
  118. MockChannelRequest.prototype.setTimeout = function(timeout) {};
  119. MockChannelRequest.prototype.setReadyStateChangeThrottle = function(throttle) {
  120. };
  121. MockChannelRequest.prototype.xmlHttpPost = function(
  122. uri, postData, decodeChunks) {
  123. this.channelDebug_.debug(
  124. '---> POST: ' + uri + ', ' + postData + ', ' + decodeChunks);
  125. this.postData_ = postData;
  126. this.requestStartTime_ = goog.now();
  127. };
  128. MockChannelRequest.prototype.xmlHttpGet = function(
  129. uri, decodeChunks, opt_noClose) {
  130. this.channelDebug_.debug(
  131. '<--- GET: ' + uri + ', ' + decodeChunks + ', ' + opt_noClose);
  132. this.requestStartTime_ = goog.now();
  133. };
  134. MockChannelRequest.prototype.sendCloseRequest = function(uri) {
  135. this.requestStartTime_ = goog.now();
  136. };
  137. MockChannelRequest.prototype.cancel = function() {
  138. this.successful_ = false;
  139. };
  140. MockChannelRequest.prototype.getSuccess = function() {
  141. return this.successful_;
  142. };
  143. MockChannelRequest.prototype.getLastError = function() {
  144. return this.lastError_;
  145. };
  146. MockChannelRequest.prototype.getLastStatusCode = function() {
  147. return this.lastStatusCode_;
  148. };
  149. MockChannelRequest.prototype.getSessionId = function() {
  150. return this.sessionId_;
  151. };
  152. MockChannelRequest.prototype.getRequestId = function() {
  153. return this.requestId_;
  154. };
  155. MockChannelRequest.prototype.getPostData = function() {
  156. return this.postData_;
  157. };
  158. MockChannelRequest.prototype.getRequestStartTime = function() {
  159. return this.requestStartTime_;
  160. };
  161. MockChannelRequest.prototype.getXhr = function() {
  162. return null;
  163. };
  164. function shouldRunTests() {
  165. return goog.labs.net.webChannel.ChannelRequest.supportsXhrStreaming();
  166. }
  167. /**
  168. * @suppress {invalidCasts} The cast from MockChannelRequest to
  169. * ChannelRequest is invalid and will not compile.
  170. */
  171. function setUpPage() {
  172. // Use our MockChannelRequests instead of the real ones.
  173. goog.labs.net.webChannel.ChannelRequest.createChannelRequest = function(
  174. channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) {
  175. return /** @type {!goog.labs.net.webChannel.ChannelRequest} */ (
  176. new MockChannelRequest(
  177. channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId));
  178. };
  179. // Mock out the stat notification code.
  180. goog.labs.net.webChannel.requestStats.notifyStatEvent = function(stat) {
  181. numStatEvents++;
  182. lastStatEvent = stat;
  183. };
  184. goog.labs.net.webChannel.requestStats.notifyTimingEvent = function(
  185. size, rtt, retries) {
  186. numTimingEvents++;
  187. lastPostSize = size;
  188. lastPostRtt = rtt;
  189. lastPostRetryCount = retries;
  190. };
  191. }
  192. function setUp() {
  193. numTimingEvents = 0;
  194. lastPostSize = null;
  195. lastPostRtt = null;
  196. lastPostRetryCount = null;
  197. mockClock = new goog.testing.MockClock(true);
  198. channel = new goog.labs.net.webChannel.WebChannelBase('1');
  199. // restore channel-test for tests that rely on the channel-test state
  200. channel.backgroundChannelTest_ = false;
  201. gotError = false;
  202. handler = new goog.labs.net.webChannel.WebChannelBase.Handler();
  203. handler.channelOpened = function() {};
  204. handler.channelError = function(channel, error) { gotError = true; };
  205. handler.channelSuccess = function(channel, maps) {
  206. deliveredMaps = goog.array.clone(maps);
  207. };
  208. /**
  209. * @suppress {checkTypes} The callback function type declaration is skipped.
  210. */
  211. handler.channelClosed = function(
  212. channel, opt_pendingMaps, opt_undeliveredMaps) {
  213. // Mock out the handler, and let it set a formatted user readable string
  214. // of the undelivered maps which we can use when verifying our assertions.
  215. if (opt_pendingMaps) {
  216. handler.pendingMapsString = formatArrayOfMaps(opt_pendingMaps);
  217. }
  218. if (opt_undeliveredMaps) {
  219. handler.undeliveredMapsString = formatArrayOfMaps(opt_undeliveredMaps);
  220. }
  221. };
  222. handler.channelHandleMultipleArrays = function() {};
  223. handler.channelHandleArray = function() {};
  224. channel.setHandler(handler);
  225. // Provide a predictable retry time for testing.
  226. channel.getRetryTime_ = function(retryCount) { return RETRY_TIME; };
  227. var channelDebug = new goog.labs.net.webChannel.WebChannelDebug();
  228. channelDebug.debug = function(message) { debugToWindow(message); };
  229. channel.setChannelDebug(channelDebug);
  230. numStatEvents = 0;
  231. lastStatEvent = null;
  232. }
  233. function tearDown() {
  234. mockClock.dispose();
  235. stubs.reset();
  236. debugToWindow('<hr>');
  237. }
  238. function getSingleForwardRequest() {
  239. var pool = channel.forwardChannelRequestPool_;
  240. if (!pool.hasPendingRequest()) {
  241. return null;
  242. }
  243. return pool.request_ || pool.requestPool_.getValues()[0];
  244. }
  245. /**
  246. * Helper function to return a formatted string representing an array of maps.
  247. */
  248. function formatArrayOfMaps(arrayOfMaps) {
  249. var result = [];
  250. for (var i = 0; i < arrayOfMaps.length; i++) {
  251. var map = arrayOfMaps[i];
  252. var keys = map.map.getKeys();
  253. for (var j = 0; j < keys.length; j++) {
  254. var tmp = keys[j] + ':' + map.map.get(keys[j]) +
  255. (map.context ? ':' + map.context : '');
  256. result.push(tmp);
  257. }
  258. }
  259. return result.join(', ');
  260. }
  261. function testFormatArrayOfMaps() {
  262. // This function is used in a non-trivial test, so let's verify that it works.
  263. var map1 = new goog.structs.Map();
  264. map1.set('k1', 'v1');
  265. map1.set('k2', 'v2');
  266. var map2 = new goog.structs.Map();
  267. map2.set('k3', 'v3');
  268. var map3 = new goog.structs.Map();
  269. map3.set('k4', 'v4');
  270. map3.set('k5', 'v5');
  271. map3.set('k6', 'v6');
  272. // One map.
  273. var a = [];
  274. a.push(new goog.labs.net.webChannel.Wire.QueuedMap(0, map1));
  275. assertEquals('k1:v1, k2:v2', formatArrayOfMaps(a));
  276. // Many maps.
  277. var b = [];
  278. b.push(new goog.labs.net.webChannel.Wire.QueuedMap(0, map1));
  279. b.push(new goog.labs.net.webChannel.Wire.QueuedMap(0, map2));
  280. b.push(new goog.labs.net.webChannel.Wire.QueuedMap(0, map3));
  281. assertEquals(
  282. 'k1:v1, k2:v2, k3:v3, k4:v4, k5:v5, k6:v6', formatArrayOfMaps(b));
  283. // One map with a context.
  284. var c = [];
  285. c.push(
  286. new goog.labs.net.webChannel.Wire.QueuedMap(0, map1, new String('c1')));
  287. assertEquals('k1:v1:c1, k2:v2:c1', formatArrayOfMaps(c));
  288. }
  289. /**
  290. * @param {number=} opt_serverVersion
  291. * @param {string=} opt_hostPrefix
  292. * @param {string=} opt_uriPrefix
  293. * @param {boolean=} opt_spdyEnabled
  294. */
  295. function connectForwardChannel(
  296. opt_serverVersion, opt_hostPrefix, opt_uriPrefix, opt_spdyEnabled) {
  297. stubSpdyCheck(!!opt_spdyEnabled);
  298. var uriPrefix = opt_uriPrefix || '';
  299. channel.connect(uriPrefix + '/test', uriPrefix + '/bind', null);
  300. mockClock.tick(0);
  301. completeTestConnection();
  302. completeForwardChannel(opt_serverVersion, opt_hostPrefix);
  303. }
  304. /**
  305. * @param {number=} opt_serverVersion
  306. * @param {string=} opt_hostPrefix
  307. * @param {string=} opt_uriPrefix
  308. * @param {boolean=} opt_spdyEnabled
  309. */
  310. function connect(
  311. opt_serverVersion, opt_hostPrefix, opt_uriPrefix, opt_spdyEnabled) {
  312. connectForwardChannel(
  313. opt_serverVersion, opt_hostPrefix, opt_uriPrefix, opt_spdyEnabled);
  314. completeBackChannel();
  315. }
  316. function disconnect() {
  317. channel.disconnect();
  318. mockClock.tick(0);
  319. }
  320. function completeTestConnection() {
  321. completeForwardTestConnection();
  322. completeBackTestConnection();
  323. assertEquals(
  324. goog.labs.net.webChannel.WebChannelBase.State.OPENING,
  325. channel.getState());
  326. }
  327. function completeForwardTestConnection() {
  328. channel.connectionTest_.onRequestData(
  329. channel.connectionTest_.request_, '["b"]');
  330. channel.connectionTest_.onRequestComplete(channel.connectionTest_.request_);
  331. mockClock.tick(0);
  332. }
  333. function completeBackTestConnection() {
  334. channel.connectionTest_.onRequestData(
  335. channel.connectionTest_.request_, '11111');
  336. mockClock.tick(0);
  337. }
  338. /**
  339. * @param {number=} opt_serverVersion
  340. * @param {string=} opt_hostPrefix
  341. */
  342. function completeForwardChannel(opt_serverVersion, opt_hostPrefix) {
  343. var responseData = '[[0,["c","1234567890ABCDEF",' +
  344. (opt_hostPrefix ? '"' + opt_hostPrefix + '"' : 'null') +
  345. (opt_serverVersion ? ',' + opt_serverVersion : '') + ']]]';
  346. channel.onRequestData(getSingleForwardRequest(), responseData);
  347. channel.onRequestComplete(getSingleForwardRequest());
  348. mockClock.tick(0);
  349. }
  350. function completeBackChannel() {
  351. channel.onRequestData(channel.backChannelRequest_, '[[1,["foo"]]]');
  352. channel.onRequestComplete(channel.backChannelRequest_);
  353. mockClock.tick(0);
  354. }
  355. function responseDone() {
  356. channel.onRequestData(getSingleForwardRequest(), '[1,0,0]'); // mock data
  357. channel.onRequestComplete(getSingleForwardRequest());
  358. mockClock.tick(0);
  359. }
  360. /**
  361. *
  362. * @param {number=} opt_lastArrayIdSentFromServer
  363. * @param {number=} opt_outstandingDataSize
  364. */
  365. function responseNoBackchannel(
  366. opt_lastArrayIdSentFromServer, opt_outstandingDataSize) {
  367. var responseData = goog.json.serialize(
  368. [0, opt_lastArrayIdSentFromServer, opt_outstandingDataSize]);
  369. channel.onRequestData(getSingleForwardRequest(), responseData);
  370. channel.onRequestComplete(getSingleForwardRequest());
  371. mockClock.tick(0);
  372. }
  373. function response(lastArrayIdSentFromServer, outstandingDataSize) {
  374. var responseData =
  375. goog.json.serialize([1, lastArrayIdSentFromServer, outstandingDataSize]);
  376. channel.onRequestData(getSingleForwardRequest(), responseData);
  377. channel.onRequestComplete(getSingleForwardRequest());
  378. mockClock.tick(0);
  379. }
  380. function receive(data) {
  381. channel.onRequestData(channel.backChannelRequest_, '[[1,' + data + ']]');
  382. channel.onRequestComplete(channel.backChannelRequest_);
  383. mockClock.tick(0);
  384. }
  385. function responseTimeout() {
  386. getSingleForwardRequest().lastError_ =
  387. goog.labs.net.webChannel.ChannelRequest.Error.TIMEOUT;
  388. getSingleForwardRequest().successful_ = false;
  389. channel.onRequestComplete(getSingleForwardRequest());
  390. mockClock.tick(0);
  391. }
  392. /**
  393. * @param {number=} opt_statusCode
  394. */
  395. function responseRequestFailed(opt_statusCode) {
  396. getSingleForwardRequest().lastError_ =
  397. goog.labs.net.webChannel.ChannelRequest.Error.STATUS;
  398. getSingleForwardRequest().lastStatusCode_ = opt_statusCode || 503;
  399. getSingleForwardRequest().successful_ = false;
  400. channel.onRequestComplete(getSingleForwardRequest());
  401. mockClock.tick(0);
  402. }
  403. function responseUnknownSessionId() {
  404. getSingleForwardRequest().lastError_ =
  405. goog.labs.net.webChannel.ChannelRequest.Error.UNKNOWN_SESSION_ID;
  406. getSingleForwardRequest().successful_ = false;
  407. channel.onRequestComplete(getSingleForwardRequest());
  408. mockClock.tick(0);
  409. }
  410. /**
  411. * @param {string} key
  412. * @param {string} value
  413. * @param {string=} opt_context
  414. */
  415. function sendMap(key, value, opt_context) {
  416. var map = new goog.structs.Map();
  417. map.set(key, value);
  418. channel.sendMap(map, opt_context);
  419. mockClock.tick(0);
  420. }
  421. function hasForwardChannel() {
  422. return !!getSingleForwardRequest();
  423. }
  424. function hasBackChannel() {
  425. return !!channel.backChannelRequest_;
  426. }
  427. function hasDeadBackChannelTimer() {
  428. return goog.isDefAndNotNull(channel.deadBackChannelTimerId_);
  429. }
  430. function assertHasForwardChannel() {
  431. assertTrue('Forward channel missing.', hasForwardChannel());
  432. }
  433. function assertHasBackChannel() {
  434. assertTrue('Back channel missing.', hasBackChannel());
  435. }
  436. function testConnect() {
  437. connect();
  438. assertEquals(
  439. goog.labs.net.webChannel.WebChannelBase.State.OPENED, channel.getState());
  440. // If the server specifies no version, the client assumes the latest version
  441. assertEquals(
  442. goog.labs.net.webChannel.Wire.LATEST_CHANNEL_VERSION,
  443. channel.channelVersion_);
  444. assertFalse(channel.isBuffered());
  445. }
  446. function testConnect_backChannelEstablished() {
  447. connect();
  448. assertHasBackChannel();
  449. }
  450. function testConnect_withServerHostPrefix() {
  451. connect(undefined, 'serverHostPrefix');
  452. assertEquals('serverHostPrefix', channel.hostPrefix_);
  453. }
  454. function testConnect_withClientHostPrefix() {
  455. handler.correctHostPrefix = function(hostPrefix) {
  456. return 'clientHostPrefix';
  457. };
  458. connect();
  459. assertEquals('clientHostPrefix', channel.hostPrefix_);
  460. }
  461. function testConnect_overrideServerHostPrefix() {
  462. handler.correctHostPrefix = function(hostPrefix) {
  463. return 'clientHostPrefix';
  464. };
  465. connect(undefined, 'serverHostPrefix');
  466. assertEquals('clientHostPrefix', channel.hostPrefix_);
  467. }
  468. function testConnect_withServerVersion() {
  469. connect(8);
  470. assertEquals(8, channel.channelVersion_);
  471. }
  472. function testConnect_notOkToMakeRequestForTest() {
  473. handler.okToMakeRequest = goog.functions.constant(
  474. goog.labs.net.webChannel.WebChannelBase.Error.NETWORK);
  475. channel.connect('/test', '/bind', null);
  476. mockClock.tick(0);
  477. assertEquals(
  478. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  479. }
  480. function testConnect_notOkToMakeRequestForBind() {
  481. channel.connect('/test', '/bind', null);
  482. mockClock.tick(0);
  483. completeTestConnection();
  484. handler.okToMakeRequest = goog.functions.constant(
  485. goog.labs.net.webChannel.WebChannelBase.Error.NETWORK);
  486. completeForwardChannel();
  487. assertEquals(
  488. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  489. }
  490. function testSendMap() {
  491. connect();
  492. sendMapOnce();
  493. }
  494. function testSendMapWithSpdyEnabled() {
  495. connect(undefined, undefined, undefined, true);
  496. sendMapOnce();
  497. }
  498. function sendMapOnce() {
  499. assertEquals(1, numTimingEvents);
  500. sendMap('foo', 'bar');
  501. responseDone();
  502. assertEquals(2, numTimingEvents);
  503. assertEquals('foo:bar', formatArrayOfMaps(deliveredMaps));
  504. }
  505. function testSendMap_twice() {
  506. connect();
  507. sendMapTwice();
  508. }
  509. function testSendMap_twiceWithSpdyEnabled() {
  510. connect(undefined, undefined, undefined, true);
  511. sendMapTwice();
  512. }
  513. function sendMapTwice() {
  514. sendMap('foo1', 'bar1');
  515. responseDone();
  516. assertEquals('foo1:bar1', formatArrayOfMaps(deliveredMaps));
  517. sendMap('foo2', 'bar2');
  518. responseDone();
  519. assertEquals('foo2:bar2', formatArrayOfMaps(deliveredMaps));
  520. }
  521. function testSendMap_andReceive() {
  522. connect();
  523. sendMap('foo', 'bar');
  524. responseDone();
  525. receive('["the server reply"]');
  526. }
  527. function testReceive() {
  528. connect();
  529. receive('["message from server"]');
  530. assertHasBackChannel();
  531. }
  532. function testReceive_twice() {
  533. connect();
  534. receive('["message one from server"]');
  535. receive('["message two from server"]');
  536. assertHasBackChannel();
  537. }
  538. function testReceive_andSendMap() {
  539. connect();
  540. receive('["the server reply"]');
  541. sendMap('foo', 'bar');
  542. responseDone();
  543. assertHasBackChannel();
  544. }
  545. function testBackChannelRemainsEstablished_afterSingleSendMap() {
  546. connect();
  547. sendMap('foo', 'bar');
  548. responseDone();
  549. receive('["ack"]');
  550. assertHasBackChannel();
  551. }
  552. function testBackChannelRemainsEstablished_afterDoubleSendMap() {
  553. connect();
  554. sendMap('foo1', 'bar1');
  555. sendMap('foo2', 'bar2');
  556. responseDone();
  557. receive('["ack"]');
  558. // This assertion would fail prior to CL 13302660.
  559. assertHasBackChannel();
  560. }
  561. function testTimingEvent() {
  562. connect();
  563. assertEquals(1, numTimingEvents);
  564. sendMap('', '');
  565. assertEquals(1, numTimingEvents);
  566. mockClock.tick(20);
  567. var expSize = getSingleForwardRequest().getPostData().length;
  568. responseDone();
  569. assertEquals(2, numTimingEvents);
  570. assertEquals(expSize, lastPostSize);
  571. assertEquals(20, lastPostRtt);
  572. assertEquals(0, lastPostRetryCount);
  573. sendMap('abcdefg', '123456');
  574. expSize = getSingleForwardRequest().getPostData().length;
  575. responseTimeout();
  576. assertEquals(2, numTimingEvents);
  577. mockClock.tick(RETRY_TIME + 1);
  578. responseDone();
  579. assertEquals(3, numTimingEvents);
  580. assertEquals(expSize, lastPostSize);
  581. assertEquals(1, lastPostRetryCount);
  582. assertEquals(1, lastPostRtt);
  583. }
  584. /**
  585. * Make sure that dropping the forward channel retry limit below the retry count
  586. * reports an error, and prevents another request from firing.
  587. */
  588. function testSetFailFastWhileWaitingForRetry() {
  589. stubNetUtils();
  590. connect();
  591. setFailFastWhileWaitingForRetry();
  592. }
  593. function testSetFailFastWhileWaitingForRetryWithSpdyEnabled() {
  594. stubNetUtils();
  595. connect(undefined, undefined, undefined, true);
  596. setFailFastWhileWaitingForRetry();
  597. }
  598. function setFailFastWhileWaitingForRetry() {
  599. assertEquals(1, numTimingEvents);
  600. sendMap('foo', 'bar');
  601. assertNull(channel.forwardChannelTimerId_);
  602. assertNotNull(getSingleForwardRequest());
  603. assertEquals(0, channel.forwardChannelRetryCount_);
  604. // Watchdog timeout.
  605. responseTimeout();
  606. assertNotNull(channel.forwardChannelTimerId_);
  607. assertNull(getSingleForwardRequest());
  608. assertEquals(1, channel.forwardChannelRetryCount_);
  609. // Almost finish the between-retry timeout.
  610. mockClock.tick(RETRY_TIME - 1);
  611. assertNotNull(channel.forwardChannelTimerId_);
  612. assertNull(getSingleForwardRequest());
  613. assertEquals(1, channel.forwardChannelRetryCount_);
  614. // Setting max retries to 0 should cancel the timer and raise an error.
  615. channel.setFailFast(true);
  616. assertNull(channel.forwardChannelTimerId_);
  617. assertNull(getSingleForwardRequest());
  618. assertEquals(1, channel.forwardChannelRetryCount_);
  619. // We get the error immediately before starting to ping google.com.
  620. assertTrue(gotError);
  621. assertEquals(0, deliveredMaps.length);
  622. // Simulate that timing out. We should not get another error.
  623. gotError = false;
  624. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT);
  625. assertFalse('Extra error after network ping timed out.', gotError);
  626. // Make sure no more retry timers are firing.
  627. mockClock.tick(ALL_DAY_MS);
  628. assertNull(channel.forwardChannelTimerId_);
  629. assertNull(getSingleForwardRequest());
  630. assertEquals(1, channel.forwardChannelRetryCount_);
  631. assertEquals(1, numTimingEvents);
  632. }
  633. /**
  634. * Make sure that dropping the forward channel retry limit below the retry count
  635. * reports an error, and prevents another request from firing.
  636. */
  637. function testSetFailFastWhileRetryXhrIsInFlight() {
  638. stubNetUtils();
  639. connect();
  640. setFailFastWhileRetryXhrIsInFlight();
  641. }
  642. function testSetFailFastWhileRetryXhrIsInFlightWithSpdyEnabled() {
  643. stubNetUtils();
  644. connect(undefined, undefined, undefined, true);
  645. setFailFastWhileRetryXhrIsInFlight();
  646. }
  647. function setFailFastWhileRetryXhrIsInFlight() {
  648. assertEquals(1, numTimingEvents);
  649. sendMap('foo', 'bar');
  650. assertNull(channel.forwardChannelTimerId_);
  651. assertNotNull(getSingleForwardRequest());
  652. assertEquals(0, channel.forwardChannelRetryCount_);
  653. // Watchdog timeout.
  654. responseTimeout();
  655. assertNotNull(channel.forwardChannelTimerId_);
  656. assertNull(getSingleForwardRequest());
  657. assertEquals(1, channel.forwardChannelRetryCount_);
  658. // Wait for the between-retry timeout.
  659. mockClock.tick(RETRY_TIME);
  660. assertNull(channel.forwardChannelTimerId_);
  661. assertNotNull(getSingleForwardRequest());
  662. assertEquals(1, channel.forwardChannelRetryCount_);
  663. // Simulate a second watchdog timeout.
  664. responseTimeout();
  665. assertNotNull(channel.forwardChannelTimerId_);
  666. assertNull(getSingleForwardRequest());
  667. assertEquals(2, channel.forwardChannelRetryCount_);
  668. // Wait for another between-retry timeout.
  669. mockClock.tick(RETRY_TIME);
  670. // Now the third req is in flight.
  671. assertNull(channel.forwardChannelTimerId_);
  672. assertNotNull(getSingleForwardRequest());
  673. assertEquals(2, channel.forwardChannelRetryCount_);
  674. // Set fail fast, killing the request
  675. channel.setFailFast(true);
  676. assertNull(channel.forwardChannelTimerId_);
  677. assertNull(getSingleForwardRequest());
  678. assertEquals(2, channel.forwardChannelRetryCount_);
  679. // We get the error immediately before starting to ping google.com.
  680. assertTrue(gotError);
  681. // Simulate that timing out. We should not get another error.
  682. gotError = false;
  683. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT);
  684. assertFalse('Extra error after network ping timed out.', gotError);
  685. // Make sure no more retry timers are firing.
  686. mockClock.tick(ALL_DAY_MS);
  687. assertNull(channel.forwardChannelTimerId_);
  688. assertNull(getSingleForwardRequest());
  689. assertEquals(2, channel.forwardChannelRetryCount_);
  690. assertEquals(1, numTimingEvents);
  691. }
  692. /**
  693. * Makes sure that setting fail fast while not retrying doesn't cause a failure.
  694. */
  695. function testSetFailFastAtRetryCount() {
  696. stubNetUtils();
  697. connect();
  698. assertEquals(1, numTimingEvents);
  699. sendMap('foo', 'bar');
  700. assertNull(channel.forwardChannelTimerId_);
  701. assertNotNull(getSingleForwardRequest());
  702. assertEquals(0, channel.forwardChannelRetryCount_);
  703. // Set fail fast.
  704. channel.setFailFast(true);
  705. // Request should still be alive.
  706. assertNull(channel.forwardChannelTimerId_);
  707. assertNotNull(getSingleForwardRequest());
  708. assertEquals(0, channel.forwardChannelRetryCount_);
  709. // Watchdog timeout. Now we should get an error.
  710. responseTimeout();
  711. assertNull(channel.forwardChannelTimerId_);
  712. assertNull(getSingleForwardRequest());
  713. assertEquals(0, channel.forwardChannelRetryCount_);
  714. // We get the error immediately before starting to ping google.com.
  715. assertTrue(gotError);
  716. // We get the error immediately before starting to ping google.com.
  717. // Simulate that timing out. We should not get another error in addition
  718. // to the initial failure.
  719. gotError = false;
  720. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT);
  721. assertFalse('Extra error after network ping timed out.', gotError);
  722. // Make sure no more retry timers are firing.
  723. mockClock.tick(ALL_DAY_MS);
  724. assertNull(channel.forwardChannelTimerId_);
  725. assertNull(getSingleForwardRequest());
  726. assertEquals(0, channel.forwardChannelRetryCount_);
  727. assertEquals(1, numTimingEvents);
  728. }
  729. function testRequestFailedClosesChannel() {
  730. stubNetUtils();
  731. connect();
  732. requestFailedClosesChannel();
  733. }
  734. function testRequestFailedClosesChannelWithSpdyEnabled() {
  735. stubNetUtils();
  736. connect(undefined, undefined, undefined, true);
  737. requestFailedClosesChannel();
  738. }
  739. function requestFailedClosesChannel() {
  740. assertEquals(1, numTimingEvents);
  741. sendMap('foo', 'bar');
  742. responseRequestFailed();
  743. assertEquals(
  744. 'Should be closed immediately after request failed.',
  745. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  746. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT);
  747. assertEquals(
  748. 'Should remain closed after the ping timeout.',
  749. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  750. assertEquals(1, numTimingEvents);
  751. }
  752. function testStatEventReportedOnlyOnce() {
  753. stubNetUtils();
  754. connect();
  755. sendMap('foo', 'bar');
  756. numStatEvents = 0;
  757. lastStatEvent = null;
  758. responseUnknownSessionId();
  759. assertEquals(1, numStatEvents);
  760. assertEquals(
  761. goog.labs.net.webChannel.requestStats.Stat.ERROR_OTHER, lastStatEvent);
  762. numStatEvents = 0;
  763. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT);
  764. assertEquals('No new stat events should be reported.', 0, numStatEvents);
  765. }
  766. function testStatEventReportedOnlyOnce_onNetworkUp() {
  767. stubNetUtils();
  768. connect();
  769. sendMap('foo', 'bar');
  770. numStatEvents = 0;
  771. lastStatEvent = null;
  772. responseRequestFailed();
  773. assertEquals(
  774. 'No stat event should be reported before we know the reason.', 0,
  775. numStatEvents);
  776. // Let the ping time out.
  777. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT);
  778. // Assert we report the correct stat event.
  779. assertEquals(1, numStatEvents);
  780. assertEquals(
  781. goog.labs.net.webChannel.requestStats.Stat.ERROR_NETWORK, lastStatEvent);
  782. }
  783. function testStatEventReportedOnlyOnce_onNetworkDown() {
  784. stubNetUtils();
  785. connect();
  786. sendMap('foo', 'bar');
  787. numStatEvents = 0;
  788. lastStatEvent = null;
  789. responseRequestFailed();
  790. assertEquals(
  791. 'No stat event should be reported before we know the reason.', 0,
  792. numStatEvents);
  793. // Wait half the ping timeout period, and then fake the network being up.
  794. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT / 2);
  795. channel.testNetworkCallback_(true);
  796. // Assert we report the correct stat event.
  797. assertEquals(1, numStatEvents);
  798. assertEquals(
  799. goog.labs.net.webChannel.requestStats.Stat.ERROR_OTHER, lastStatEvent);
  800. }
  801. function testOutgoingMapsAwaitsResponse() {
  802. connect();
  803. outgoingMapsAwaitsResponse();
  804. }
  805. function testOutgoingMapsAwaitsResponseWithSpdyEnabled() {
  806. connect(undefined, undefined, undefined, true);
  807. outgoingMapsAwaitsResponse();
  808. }
  809. function outgoingMapsAwaitsResponse() {
  810. assertEquals(0, channel.outgoingMaps_.length);
  811. sendMap('foo1', 'bar');
  812. assertEquals(0, channel.outgoingMaps_.length);
  813. sendMap('foo2', 'bar');
  814. assertEquals(1, channel.outgoingMaps_.length);
  815. sendMap('foo3', 'bar');
  816. assertEquals(2, channel.outgoingMaps_.length);
  817. sendMap('foo4', 'bar');
  818. assertEquals(3, channel.outgoingMaps_.length);
  819. responseDone();
  820. // Now the forward channel request is completed and a new started, so all maps
  821. // are dequeued from the array of outgoing maps into this new forward request.
  822. assertEquals(0, channel.outgoingMaps_.length);
  823. }
  824. function testUndeliveredMaps_doesNotNotifyWhenSuccessful() {
  825. /**
  826. * @suppress {checkTypes} The callback function type declaration is skipped.
  827. */
  828. handler.channelClosed = function(
  829. channel, opt_pendingMaps, opt_undeliveredMaps) {
  830. if (opt_pendingMaps || opt_undeliveredMaps) {
  831. fail('No pending or undelivered maps should be reported.');
  832. }
  833. };
  834. connect();
  835. sendMap('foo1', 'bar1');
  836. responseDone();
  837. sendMap('foo2', 'bar2');
  838. responseDone();
  839. disconnect();
  840. }
  841. function testUndeliveredMaps_doesNotNotifyIfNothingWasSent() {
  842. /**
  843. * @suppress {checkTypes} The callback function type declaration is skipped.
  844. */
  845. handler.channelClosed = function(
  846. channel, opt_pendingMaps, opt_undeliveredMaps) {
  847. if (opt_pendingMaps || opt_undeliveredMaps) {
  848. fail('No pending or undelivered maps should be reported.');
  849. }
  850. };
  851. connect();
  852. mockClock.tick(ALL_DAY_MS);
  853. disconnect();
  854. }
  855. function testUndeliveredMaps_clearsPendingMapsAfterNotifying() {
  856. connect();
  857. sendMap('foo1', 'bar1');
  858. sendMap('foo2', 'bar2');
  859. sendMap('foo3', 'bar3');
  860. assertEquals(1, channel.pendingMaps_.length);
  861. assertEquals(2, channel.outgoingMaps_.length);
  862. disconnect();
  863. assertEquals(0, channel.pendingMaps_.length);
  864. assertEquals(0, channel.outgoingMaps_.length);
  865. }
  866. function testUndeliveredMaps_notifiesWithContext() {
  867. connect();
  868. // First send two messages that succeed.
  869. sendMap('foo1', 'bar1', 'context1');
  870. responseDone();
  871. sendMap('foo2', 'bar2', 'context2');
  872. responseDone();
  873. // Pretend the server hangs and no longer responds.
  874. sendMap('foo3', 'bar3', 'context3');
  875. sendMap('foo4', 'bar4', 'context4');
  876. sendMap('foo5', 'bar5', 'context5');
  877. // Give up.
  878. disconnect();
  879. // Assert that we are informed of any undelivered messages; both about
  880. // #3 that was sent but which we don't know if the server received, and
  881. // #4 and #5 which remain in the outgoing maps and have not yet been sent.
  882. assertEquals('foo3:bar3:context3', handler.pendingMapsString);
  883. assertEquals(
  884. 'foo4:bar4:context4, foo5:bar5:context5', handler.undeliveredMapsString);
  885. }
  886. function testUndeliveredMaps_serviceUnavailable() {
  887. // Send a few maps, and let one fail.
  888. connect();
  889. sendMap('foo1', 'bar1');
  890. responseDone();
  891. sendMap('foo2', 'bar2');
  892. responseRequestFailed();
  893. // After a failure, the channel should be closed.
  894. disconnect();
  895. assertEquals('foo2:bar2', handler.pendingMapsString);
  896. assertEquals('', handler.undeliveredMapsString);
  897. }
  898. function testUndeliveredMaps_onPingTimeout() {
  899. stubNetUtils();
  900. connect();
  901. // Send a message.
  902. sendMap('foo1', 'bar1');
  903. // Fake REQUEST_FAILED, triggering a ping to check the network.
  904. responseRequestFailed();
  905. // Let the ping time out, unsuccessfully.
  906. mockClock.tick(goog.labs.net.webChannel.netUtils.NETWORK_TIMEOUT);
  907. // Assert channel is closed.
  908. assertEquals(
  909. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  910. // Assert that the handler is notified about the undelivered messages.
  911. assertEquals('foo1:bar1', handler.pendingMapsString);
  912. assertEquals('', handler.undeliveredMapsString);
  913. }
  914. function testResponseNoBackchannelPostNotBeforeBackchannel() {
  915. connect(8);
  916. sendMap('foo1', 'bar1');
  917. mockClock.tick(10);
  918. assertFalse(
  919. channel.backChannelRequest_.getRequestStartTime() <
  920. getSingleForwardRequest().getRequestStartTime());
  921. responseNoBackchannel();
  922. assertNotEquals(
  923. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_MISSING,
  924. lastStatEvent);
  925. }
  926. function testResponseNoBackchannel() {
  927. connect(8);
  928. sendMap('foo1', 'bar1');
  929. response(-1, 0);
  930. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE + 1);
  931. sendMap('foo2', 'bar2');
  932. assertTrue(
  933. channel.backChannelRequest_.getRequestStartTime() +
  934. goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE <
  935. getSingleForwardRequest().getRequestStartTime());
  936. responseNoBackchannel();
  937. assertEquals(
  938. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_MISSING,
  939. lastStatEvent);
  940. }
  941. function testResponseNoBackchannelWithNoBackchannel() {
  942. connect(8);
  943. sendMap('foo1', 'bar1');
  944. assertNull(channel.backChannelTimerId_);
  945. channel.backChannelRequest_.cancel();
  946. channel.backChannelRequest_ = null;
  947. responseNoBackchannel();
  948. assertEquals(
  949. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_MISSING,
  950. lastStatEvent);
  951. }
  952. function testResponseNoBackchannelWithStartTimer() {
  953. connect(8);
  954. sendMap('foo1', 'bar1');
  955. channel.backChannelRequest_.cancel();
  956. channel.backChannelRequest_ = null;
  957. channel.backChannelTimerId_ = 123;
  958. responseNoBackchannel();
  959. assertNotEquals(
  960. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_MISSING,
  961. lastStatEvent);
  962. }
  963. function testResponseWithNoArraySent() {
  964. connect(8);
  965. sendMap('foo1', 'bar1');
  966. // Send a response as if the server hasn't sent down an array.
  967. response(-1, 0);
  968. // POST response with an array ID lower than our last received is OK.
  969. assertEquals(1, channel.lastArrayId_);
  970. assertEquals(-1, channel.lastPostResponseArrayId_);
  971. }
  972. function testResponseWithArraysMissing() {
  973. connect(8);
  974. sendMap('foo1', 'bar1');
  975. assertEquals(-1, channel.lastPostResponseArrayId_);
  976. // Send a response as if the server has sent down seven arrays.
  977. response(7, 111);
  978. assertEquals(1, channel.lastArrayId_);
  979. assertEquals(7, channel.lastPostResponseArrayId_);
  980. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE * 2);
  981. assertEquals(
  982. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_DEAD,
  983. lastStatEvent);
  984. }
  985. function testMultipleResponsesWithArraysMissing() {
  986. connect(8);
  987. sendMap('foo1', 'bar1');
  988. assertEquals(-1, channel.lastPostResponseArrayId_);
  989. // Send a response as if the server has sent down seven arrays.
  990. response(7, 111);
  991. assertEquals(1, channel.lastArrayId_);
  992. assertEquals(7, channel.lastPostResponseArrayId_);
  993. sendMap('foo2', 'bar2');
  994. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE);
  995. response(8, 119);
  996. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE);
  997. // The original timer should still fire.
  998. assertEquals(
  999. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_DEAD,
  1000. lastStatEvent);
  1001. }
  1002. function testOnlyRetryOnceBasedOnResponse() {
  1003. connect(8);
  1004. sendMap('foo1', 'bar1');
  1005. assertEquals(-1, channel.lastPostResponseArrayId_);
  1006. // Send a response as if the server has sent down seven arrays.
  1007. response(7, 111);
  1008. assertEquals(1, channel.lastArrayId_);
  1009. assertEquals(7, channel.lastPostResponseArrayId_);
  1010. assertTrue(hasDeadBackChannelTimer());
  1011. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE * 2);
  1012. assertEquals(
  1013. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_DEAD,
  1014. lastStatEvent);
  1015. assertEquals(1, channel.backChannelRetryCount_);
  1016. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE);
  1017. sendMap('foo2', 'bar2');
  1018. assertFalse(hasDeadBackChannelTimer());
  1019. response(8, 119);
  1020. assertFalse(hasDeadBackChannelTimer());
  1021. }
  1022. function testResponseWithArraysMissingAndLiveChannel() {
  1023. connect(8);
  1024. sendMap('foo1', 'bar1');
  1025. assertEquals(-1, channel.lastPostResponseArrayId_);
  1026. // Send a response as if the server has sent down seven arrays.
  1027. response(7, 111);
  1028. assertEquals(1, channel.lastArrayId_);
  1029. assertEquals(7, channel.lastPostResponseArrayId_);
  1030. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE);
  1031. assertTrue(hasDeadBackChannelTimer());
  1032. receive('["ack"]');
  1033. assertFalse(hasDeadBackChannelTimer());
  1034. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE);
  1035. assertNotEquals(
  1036. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_DEAD,
  1037. lastStatEvent);
  1038. }
  1039. function testResponseWithBigOutstandingData() {
  1040. connect(8);
  1041. sendMap('foo1', 'bar1');
  1042. assertEquals(-1, channel.lastPostResponseArrayId_);
  1043. // Send a response as if the server has sent down seven arrays and 50kbytes.
  1044. response(7, 50000);
  1045. assertEquals(1, channel.lastArrayId_);
  1046. assertEquals(7, channel.lastPostResponseArrayId_);
  1047. assertFalse(hasDeadBackChannelTimer());
  1048. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE * 2);
  1049. assertNotEquals(
  1050. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_DEAD,
  1051. lastStatEvent);
  1052. }
  1053. function testResponseInBufferedMode() {
  1054. connect(8);
  1055. channel.useChunked_ = false;
  1056. sendMap('foo1', 'bar1');
  1057. assertEquals(-1, channel.lastPostResponseArrayId_);
  1058. response(7, 111);
  1059. assertEquals(1, channel.lastArrayId_);
  1060. assertEquals(7, channel.lastPostResponseArrayId_);
  1061. assertFalse(hasDeadBackChannelTimer());
  1062. mockClock.tick(goog.labs.net.webChannel.WebChannelBase.RTT_ESTIMATE * 2);
  1063. assertNotEquals(
  1064. goog.labs.net.webChannel.requestStats.Stat.BACKCHANNEL_DEAD,
  1065. lastStatEvent);
  1066. }
  1067. function testResponseWithGarbage() {
  1068. connect(8);
  1069. sendMap('foo1', 'bar1');
  1070. channel.onRequestData(getSingleForwardRequest(), 'garbage');
  1071. assertEquals(
  1072. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  1073. }
  1074. function testResponseWithGarbageInArray() {
  1075. connect(8);
  1076. sendMap('foo1', 'bar1');
  1077. channel.onRequestData(getSingleForwardRequest(), '["garbage"]');
  1078. assertEquals(
  1079. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  1080. }
  1081. function testResponseWithEvilData() {
  1082. connect(8);
  1083. sendMap('foo1', 'bar1');
  1084. channel.onRequestData(
  1085. getSingleForwardRequest(), 'foo=<script>evil()\<\/script>&' +
  1086. 'bar=<script>moreEvil()\<\/script>');
  1087. assertEquals(
  1088. goog.labs.net.webChannel.WebChannelBase.State.CLOSED, channel.getState());
  1089. }
  1090. function testPathAbsolute() {
  1091. connect(8, undefined, '/talkgadget');
  1092. assertEquals(channel.backChannelUri_.getDomain(), window.location.hostname);
  1093. assertEquals(
  1094. channel.forwardChannelUri_.getDomain(), window.location.hostname);
  1095. }
  1096. function testPathRelative() {
  1097. connect(8, undefined, 'talkgadget');
  1098. assertEquals(channel.backChannelUri_.getDomain(), window.location.hostname);
  1099. assertEquals(
  1100. channel.forwardChannelUri_.getDomain(), window.location.hostname);
  1101. }
  1102. function testPathWithHost() {
  1103. connect(8, undefined, 'https://example.com');
  1104. assertEquals(channel.backChannelUri_.getScheme(), 'https');
  1105. assertEquals(channel.backChannelUri_.getDomain(), 'example.com');
  1106. assertEquals(channel.forwardChannelUri_.getScheme(), 'https');
  1107. assertEquals(channel.forwardChannelUri_.getDomain(), 'example.com');
  1108. }
  1109. function testCreateXhrIo() {
  1110. var xhr = channel.createXhrIo(null);
  1111. assertFalse(xhr.getWithCredentials());
  1112. assertThrows(
  1113. 'Error connection to different host without CORS',
  1114. goog.bind(channel.createXhrIo, channel, 'some_host'));
  1115. channel.setSupportsCrossDomainXhrs(true);
  1116. xhr = channel.createXhrIo(null);
  1117. assertTrue(xhr.getWithCredentials());
  1118. xhr = channel.createXhrIo('some_host');
  1119. assertTrue(xhr.getWithCredentials());
  1120. }
  1121. function testSpdyLimitOption() {
  1122. var webChannelTransport =
  1123. new goog.labs.net.webChannel.WebChannelBaseTransport();
  1124. stubSpdyCheck(true);
  1125. var webChannelDefault = webChannelTransport.createWebChannel('/foo');
  1126. assertEquals(
  1127. 10, webChannelDefault.getRuntimeProperties().getConcurrentRequestLimit());
  1128. assertTrue(webChannelDefault.getRuntimeProperties().isSpdyEnabled());
  1129. var options = {'concurrentRequestLimit': 100};
  1130. stubSpdyCheck(false);
  1131. var webChannelDisabled =
  1132. webChannelTransport.createWebChannel('/foo', options);
  1133. assertEquals(
  1134. 1, webChannelDisabled.getRuntimeProperties().getConcurrentRequestLimit());
  1135. assertFalse(webChannelDisabled.getRuntimeProperties().isSpdyEnabled());
  1136. stubSpdyCheck(true);
  1137. var webChannelEnabled = webChannelTransport.createWebChannel('/foo', options);
  1138. assertEquals(
  1139. 100,
  1140. webChannelEnabled.getRuntimeProperties().getConcurrentRequestLimit());
  1141. assertTrue(webChannelEnabled.getRuntimeProperties().isSpdyEnabled());
  1142. }