GULNetworkTest.m 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. // Copyright 2018 Google
  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. #import "GTMHTTPServer.h"
  15. #import <OCMock/OCMock.h>
  16. #import <XCTest/XCTest.h>
  17. #import <GoogleUtilities/GULNSData+zlib.h>
  18. #import <GoogleUtilities/GULNetwork.h>
  19. #import <GoogleUtilities/GULReachabilityChecker.h>
  20. @interface GULNetwork ()
  21. - (void)reachability:(GULReachabilityChecker *)reachability
  22. statusChanged:(GULReachabilityStatus)status;
  23. @end
  24. @interface GULNetworkURLSession ()
  25. - (void)maybeRemoveTempFilesAtURL:(NSURL *)tempFile expiringTime:(NSTimeInterval)expiringTime;
  26. @end
  27. @interface GULNetworkTest : XCTestCase <GULNetworkReachabilityDelegate>
  28. @end
  29. @implementation GULNetworkTest {
  30. dispatch_queue_t _backgroundQueue;
  31. GULNetwork *_network;
  32. /// Fake Server.
  33. GTMHTTPServer *_httpServer;
  34. GTMHTTPRequestMessage *_request;
  35. int _statusCode;
  36. // For network reachability test.
  37. BOOL _fakeNetworkIsReachable;
  38. BOOL _currentNetworkStatus;
  39. GULReachabilityStatus _fakeReachabilityStatus;
  40. }
  41. #pragma mark - Setup and teardown
  42. - (void)setUp {
  43. [super setUp];
  44. _fakeNetworkIsReachable = YES;
  45. _statusCode = 200;
  46. _request = nil;
  47. _httpServer = [[GTMHTTPServer alloc] initWithDelegate:self];
  48. // Start the server.
  49. NSError *error = nil;
  50. XCTAssertTrue([_httpServer start:&error], @"Failed to start HTTP server: %@", error);
  51. _network = [[GULNetwork alloc] init];
  52. _backgroundQueue = dispatch_queue_create("Test queue", DISPATCH_QUEUE_SERIAL);
  53. _request = nil;
  54. }
  55. - (void)tearDown {
  56. _network = nil;
  57. _backgroundQueue = nil;
  58. _request = nil;
  59. [_httpServer stop];
  60. _httpServer = nil;
  61. [super tearDown];
  62. }
  63. #pragma mark - Test reachability
  64. - (void)testReachability {
  65. _network.reachabilityDelegate = self;
  66. id reachability = [_network valueForKey:@"_reachability"];
  67. XCTAssertNotNil(reachability);
  68. id reachabilityMock = OCMPartialMock(reachability);
  69. [[[reachabilityMock stub] andCall:@selector(reachabilityStatus)
  70. onObject:self] reachabilityStatus];
  71. // Fake scenario with connectivity.
  72. _fakeNetworkIsReachable = YES;
  73. _fakeReachabilityStatus = kGULReachabilityViaWifi;
  74. [_network reachability:reachabilityMock statusChanged:[reachabilityMock reachabilityStatus]];
  75. XCTAssertTrue([_network isNetworkConnected]);
  76. XCTAssertEqual(_currentNetworkStatus, _fakeNetworkIsReachable);
  77. // Fake scenario without connectivity.
  78. _fakeNetworkIsReachable = NO;
  79. _fakeReachabilityStatus = kGULReachabilityNotReachable;
  80. [_network reachability:reachabilityMock statusChanged:[reachabilityMock reachabilityStatus]];
  81. XCTAssertFalse([_network isNetworkConnected]);
  82. XCTAssertEqual(_currentNetworkStatus, _fakeNetworkIsReachable);
  83. [reachabilityMock stopMocking];
  84. reachabilityMock = nil;
  85. }
  86. #pragma mark - Test POST Foreground
  87. - (void)testSessionNetwork_POST_foreground {
  88. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  89. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  90. NSURL *url =
  91. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/2", _httpServer.port]];
  92. _statusCode = 200;
  93. [_network postURL:url
  94. payload:uncompressedData
  95. queue:_backgroundQueue
  96. usingBackgroundSession:NO
  97. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  98. [self verifyResponse:response error:error];
  99. [self verifyRequest];
  100. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  101. [expectation fulfill];
  102. }];
  103. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  104. // Wait a little bit so the server has enough time to respond.
  105. [self waitForExpectationsWithTimeout:10
  106. handler:^(NSError *error) {
  107. if (error) {
  108. XCTFail(@"Timeout Error: %@", error);
  109. }
  110. }];
  111. }
  112. - (void)testSessionNetworkShouldReturnError_POST_foreground {
  113. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  114. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  115. NSURL *url =
  116. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/3", _httpServer.port]];
  117. _statusCode = 500;
  118. [_network postURL:url
  119. payload:uncompressedData
  120. queue:_backgroundQueue
  121. usingBackgroundSession:NO
  122. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  123. XCTAssertEqual(((NSHTTPURLResponse *)response).statusCode, 500);
  124. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  125. [expectation fulfill];
  126. }];
  127. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  128. // Wait a little bit so the server has enough time to respond.
  129. [self waitForExpectationsWithTimeout:10
  130. handler:^(NSError *error) {
  131. if (error) {
  132. XCTFail(@"Timeout Error: %@", error);
  133. }
  134. }];
  135. }
  136. - (void)testNilURLNSURLSession_POST_foreground {
  137. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  138. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  139. _statusCode = 200;
  140. [_network postURL:nil
  141. payload:uncompressedData
  142. queue:_backgroundQueue
  143. usingBackgroundSession:NO
  144. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  145. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  146. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  147. [expectation fulfill];
  148. }];
  149. [self waitForExpectationsWithTimeout:10
  150. handler:^(NSError *error) {
  151. if (error) {
  152. XCTFail(@"Timeout Error: %@", error);
  153. }
  154. }];
  155. }
  156. - (void)testEmptyURLNSURLSession_POST_foreground {
  157. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  158. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  159. _statusCode = 200;
  160. [_network postURL:[NSURL URLWithString:@""]
  161. payload:uncompressedData
  162. queue:_backgroundQueue
  163. usingBackgroundSession:NO
  164. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  165. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  166. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  167. [expectation fulfill];
  168. }];
  169. [self waitForExpectationsWithTimeout:10
  170. handler:^(NSError *error) {
  171. if (error) {
  172. XCTFail(@"Timeout Error: %@", error);
  173. }
  174. }];
  175. }
  176. - (void)testEmptyPayloadNSURLSession_POST_foreground {
  177. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  178. NSData *uncompressedData = [[NSData alloc] init];
  179. NSURL *url =
  180. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/2", _httpServer.port]];
  181. _statusCode = 200;
  182. [_network postURL:url
  183. payload:uncompressedData
  184. queue:_backgroundQueue
  185. usingBackgroundSession:NO
  186. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  187. XCTAssertNil(error);
  188. XCTAssertNotNil(self->_request);
  189. XCTAssertEqualObjects([self->_request.URL absoluteString], [url absoluteString]);
  190. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  191. [expectation fulfill];
  192. }];
  193. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  194. [self waitForExpectationsWithTimeout:10
  195. handler:^(NSError *error) {
  196. if (error) {
  197. XCTFail(@"Timeout Error: %@", error);
  198. }
  199. }];
  200. }
  201. - (void)testNilQueueNSURLSession_POST_foreground {
  202. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  203. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  204. NSURL *url =
  205. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/1", _httpServer.port]];
  206. _statusCode = 200;
  207. [_network postURL:url
  208. payload:uncompressedData
  209. queue:nil
  210. usingBackgroundSession:NO
  211. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  212. [self verifyResponse:response error:error];
  213. [self verifyRequest];
  214. [expectation fulfill];
  215. }];
  216. // Wait a little bit so the server has enough time to respond.
  217. [self waitForExpectationsWithTimeout:10
  218. handler:^(NSError *error) {
  219. if (error) {
  220. XCTFail(@"Timeout Error: %@", error);
  221. }
  222. }];
  223. }
  224. - (void)testHasRequestPendingNSURLSession_POST_foreground {
  225. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  226. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  227. NSURL *url =
  228. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/hasRequestPending",
  229. _httpServer.port]];
  230. _statusCode = 200;
  231. [_network postURL:url
  232. payload:uncompressedData
  233. queue:_backgroundQueue
  234. usingBackgroundSession:NO
  235. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  236. [self verifyResponse:response error:error];
  237. [self verifyRequest];
  238. XCTAssertFalse(self->_network.hasUploadInProgress,
  239. @"hasUploadInProgress must be false");
  240. [expectation fulfill];
  241. }];
  242. XCTAssertTrue(self->_network.hasUploadInProgress, @"hasUploadInProgress must be true");
  243. // Wait a little bit so the server has enough time to respond.
  244. [self waitForExpectationsWithTimeout:10
  245. handler:^(NSError *error) {
  246. if (error) {
  247. XCTFail(@"Timeout Error: %@", error);
  248. }
  249. }];
  250. }
  251. #pragma mark - Test POST Background
  252. - (void)testSessionNetwork_POST_background {
  253. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  254. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  255. NSURL *url =
  256. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/2", _httpServer.port]];
  257. _statusCode = 200;
  258. [_network postURL:url
  259. payload:uncompressedData
  260. queue:_backgroundQueue
  261. usingBackgroundSession:YES
  262. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  263. [self verifyResponse:response error:error];
  264. [self verifyRequest];
  265. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  266. [expectation fulfill];
  267. }];
  268. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  269. // Wait a little bit so the server has enough time to respond.
  270. [self waitForExpectationsWithTimeout:10
  271. handler:^(NSError *error) {
  272. if (error) {
  273. XCTFail(@"Timeout Error: %@", error);
  274. }
  275. }];
  276. }
  277. - (void)testSessionNetworkShouldReturnError_POST_background {
  278. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  279. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  280. NSURL *url =
  281. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/3", _httpServer.port]];
  282. _statusCode = 500;
  283. [_network postURL:url
  284. payload:uncompressedData
  285. queue:_backgroundQueue
  286. usingBackgroundSession:YES
  287. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  288. XCTAssertEqual(((NSHTTPURLResponse *)response).statusCode, 500);
  289. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  290. [expectation fulfill];
  291. }];
  292. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  293. // Wait a little bit so the server has enough time to respond.
  294. [self waitForExpectationsWithTimeout:10
  295. handler:^(NSError *error) {
  296. if (error) {
  297. XCTFail(@"Timeout Error: %@", error);
  298. }
  299. }];
  300. }
  301. - (void)testNilURLNSURLSession_POST_background {
  302. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  303. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  304. _statusCode = 200;
  305. [_network postURL:nil
  306. payload:uncompressedData
  307. queue:_backgroundQueue
  308. usingBackgroundSession:YES
  309. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  310. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  311. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  312. [expectation fulfill];
  313. }];
  314. [self waitForExpectationsWithTimeout:10
  315. handler:^(NSError *error) {
  316. if (error) {
  317. XCTFail(@"Timeout Error: %@", error);
  318. }
  319. }];
  320. }
  321. - (void)testEmptyURLNSURLSession_POST_background {
  322. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  323. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  324. _statusCode = 200;
  325. [_network postURL:[NSURL URLWithString:@""]
  326. payload:uncompressedData
  327. queue:_backgroundQueue
  328. usingBackgroundSession:YES
  329. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  330. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  331. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  332. [expectation fulfill];
  333. }];
  334. [self waitForExpectationsWithTimeout:10
  335. handler:^(NSError *error) {
  336. if (error) {
  337. XCTFail(@"Timeout Error: %@", error);
  338. }
  339. }];
  340. }
  341. - (void)testEmptyPayloadNSURLSession_POST_background {
  342. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  343. NSData *uncompressedData = [[NSData alloc] init];
  344. NSURL *url =
  345. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/2", _httpServer.port]];
  346. _statusCode = 200;
  347. [_network postURL:url
  348. payload:uncompressedData
  349. queue:_backgroundQueue
  350. usingBackgroundSession:YES
  351. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  352. XCTAssertNil(error);
  353. XCTAssertNotNil(self->_request);
  354. XCTAssertEqualObjects([self->_request.URL absoluteString], [url absoluteString]);
  355. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  356. [expectation fulfill];
  357. }];
  358. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  359. [self waitForExpectationsWithTimeout:10
  360. handler:^(NSError *error) {
  361. if (error) {
  362. XCTFail(@"Timeout Error: %@", error);
  363. }
  364. }];
  365. }
  366. - (void)testNilQueueNSURLSession_POST_background {
  367. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  368. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  369. NSURL *url =
  370. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/1", _httpServer.port]];
  371. _statusCode = 200;
  372. [_network postURL:url
  373. payload:uncompressedData
  374. queue:nil
  375. usingBackgroundSession:YES
  376. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  377. [self verifyResponse:response error:error];
  378. [self verifyRequest];
  379. [expectation fulfill];
  380. }];
  381. // Wait a little bit so the server has enough time to respond.
  382. [self waitForExpectationsWithTimeout:10
  383. handler:^(NSError *error) {
  384. if (error) {
  385. XCTFail(@"Timeout Error: %@", error);
  386. }
  387. }];
  388. }
  389. - (void)testHasRequestPendingNSURLSession_POST_background {
  390. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  391. NSData *uncompressedData = [@"Google" dataUsingEncoding:NSUTF8StringEncoding];
  392. NSURL *url =
  393. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/hasRequestPending",
  394. _httpServer.port]];
  395. _statusCode = 200;
  396. [_network postURL:url
  397. payload:uncompressedData
  398. queue:_backgroundQueue
  399. usingBackgroundSession:YES
  400. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  401. [self verifyResponse:response error:error];
  402. [self verifyRequest];
  403. XCTAssertFalse(self->_network.hasUploadInProgress,
  404. @"hasUploadInProgress must be false");
  405. [expectation fulfill];
  406. }];
  407. XCTAssertTrue(self->_network.hasUploadInProgress, @"hasUploadInProgress must be true");
  408. // Wait a little bit so the server has enough time to respond.
  409. [self waitForExpectationsWithTimeout:10
  410. handler:^(NSError *error) {
  411. if (error) {
  412. XCTFail(@"Timeout Error: %@", error);
  413. }
  414. }];
  415. }
  416. #pragma mark - GET Methods Foreground
  417. - (void)testSessionNetworkAsync_GET_foreground {
  418. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  419. NSURL *url =
  420. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/2", _httpServer.port]];
  421. _statusCode = 200;
  422. [_network getURL:url
  423. headers:nil
  424. queue:_backgroundQueue
  425. usingBackgroundSession:NO
  426. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  427. XCTAssertNotNil(data);
  428. NSString *responseBody = [[NSString alloc] initWithData:data
  429. encoding:NSUTF8StringEncoding];
  430. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  431. XCTAssertNil(error);
  432. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  433. [expectation fulfill];
  434. }];
  435. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  436. // Wait a little bit so the server has enough time to respond.
  437. [self waitForExpectationsWithTimeout:10
  438. handler:^(NSError *error) {
  439. if (error) {
  440. XCTFail(@"Timeout Error: %@", error);
  441. }
  442. }];
  443. }
  444. - (void)testSessionNetworkShouldReturnError_GET_foreground {
  445. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  446. NSURL *url =
  447. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/3", _httpServer.port]];
  448. _statusCode = 500;
  449. [_network getURL:url
  450. headers:nil
  451. queue:_backgroundQueue
  452. usingBackgroundSession:NO
  453. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  454. XCTAssertEqual(((NSHTTPURLResponse *)response).statusCode, 500);
  455. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  456. [expectation fulfill];
  457. }];
  458. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  459. // Wait a little bit so the server has enough time to respond.
  460. [self waitForExpectationsWithTimeout:10
  461. handler:^(NSError *error) {
  462. if (error) {
  463. XCTFail(@"Timeout Error: %@", error);
  464. }
  465. }];
  466. }
  467. - (void)testNilURLNSURLSession_GET_foreground {
  468. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  469. _statusCode = 200;
  470. [_network getURL:nil
  471. headers:nil
  472. queue:_backgroundQueue
  473. usingBackgroundSession:NO
  474. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  475. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  476. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  477. [expectation fulfill];
  478. }];
  479. [self waitForExpectationsWithTimeout:10
  480. handler:^(NSError *error) {
  481. if (error) {
  482. XCTFail(@"Timeout Error: %@", error);
  483. }
  484. }];
  485. }
  486. - (void)testEmptyURLNSURLSession_GET_foreground {
  487. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  488. _statusCode = 200;
  489. [_network getURL:[NSURL URLWithString:@""]
  490. headers:nil
  491. queue:_backgroundQueue
  492. usingBackgroundSession:NO
  493. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  494. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  495. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  496. [expectation fulfill];
  497. }];
  498. [self waitForExpectationsWithTimeout:10
  499. handler:^(NSError *error) {
  500. if (error) {
  501. XCTFail(@"Timeout Error: %@", error);
  502. }
  503. }];
  504. }
  505. - (void)testNilQueueNSURLSession_GET_foreground {
  506. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  507. NSURL *url =
  508. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/1", _httpServer.port]];
  509. _statusCode = 200;
  510. [_network getURL:url
  511. headers:nil
  512. queue:nil
  513. usingBackgroundSession:NO
  514. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  515. XCTAssertNotNil(data);
  516. NSString *responseBody = [[NSString alloc] initWithData:data
  517. encoding:NSUTF8StringEncoding];
  518. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  519. XCTAssertNil(error);
  520. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  521. [expectation fulfill];
  522. }];
  523. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  524. // Wait a little bit so the server has enough time to respond.
  525. [self waitForExpectationsWithTimeout:10
  526. handler:^(NSError *error) {
  527. if (error) {
  528. XCTFail(@"Timeout Error: %@", error);
  529. }
  530. }];
  531. }
  532. - (void)testHasRequestPendingNSURLSession_GET_foreground {
  533. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  534. NSURL *url =
  535. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/hasRequestPending",
  536. _httpServer.port]];
  537. _statusCode = 200;
  538. [_network getURL:url
  539. headers:nil
  540. queue:_backgroundQueue
  541. usingBackgroundSession:NO
  542. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  543. XCTAssertNotNil(data);
  544. NSString *responseBody = [[NSString alloc] initWithData:data
  545. encoding:NSUTF8StringEncoding];
  546. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  547. XCTAssertNil(error);
  548. XCTAssertFalse(self->_network.hasUploadInProgress,
  549. @"hasUploadInProgress must be false");
  550. [expectation fulfill];
  551. }];
  552. XCTAssertTrue(self->_network.hasUploadInProgress, @"hasUploadInProgress must be true");
  553. // Wait a little bit so the server has enough time to respond.
  554. [self waitForExpectationsWithTimeout:10
  555. handler:^(NSError *error) {
  556. if (error) {
  557. XCTFail(@"Timeout Error: %@", error);
  558. }
  559. }];
  560. }
  561. - (void)testHeaders_foreground {
  562. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  563. NSURL *url =
  564. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/3", _httpServer.port]];
  565. _statusCode = 200;
  566. NSDictionary *headers = @{@"Version" : @"123"};
  567. [_network getURL:url
  568. headers:headers
  569. queue:_backgroundQueue
  570. usingBackgroundSession:NO
  571. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  572. XCTAssertNotNil(data);
  573. NSString *responseBody = [[NSString alloc] initWithData:data
  574. encoding:NSUTF8StringEncoding];
  575. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  576. XCTAssertNil(error);
  577. NSString *version = [self->_request.allHeaderFieldValues valueForKey:@"Version"];
  578. XCTAssertEqualObjects(version, @"123");
  579. [expectation fulfill];
  580. }];
  581. // Wait a little bit so the server has enough time to respond.
  582. [self waitForExpectationsWithTimeout:10
  583. handler:^(NSError *error) {
  584. if (error) {
  585. XCTFail(@"Timeout Error: %@", error);
  586. }
  587. }];
  588. }
  589. #pragma mark - GET Methods Background
  590. - (void)testSessionNetworkAsync_GET_background {
  591. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  592. NSURL *url =
  593. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/2", _httpServer.port]];
  594. _statusCode = 200;
  595. [_network getURL:url
  596. headers:nil
  597. queue:_backgroundQueue
  598. usingBackgroundSession:YES
  599. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  600. XCTAssertNotNil(data);
  601. NSString *responseBody = [[NSString alloc] initWithData:data
  602. encoding:NSUTF8StringEncoding];
  603. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  604. XCTAssertNil(error);
  605. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  606. [expectation fulfill];
  607. }];
  608. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  609. // Wait a little bit so the server has enough time to respond.
  610. [self waitForExpectationsWithTimeout:10
  611. handler:^(NSError *error) {
  612. if (error) {
  613. XCTFail(@"Timeout Error: %@", error);
  614. }
  615. }];
  616. }
  617. - (void)testSessionNetworkShouldReturnError_GET_background {
  618. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  619. NSURL *url =
  620. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/3", _httpServer.port]];
  621. _statusCode = 500;
  622. [_network getURL:url
  623. headers:nil
  624. queue:_backgroundQueue
  625. usingBackgroundSession:YES
  626. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  627. XCTAssertEqual(((NSHTTPURLResponse *)response).statusCode, 500);
  628. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  629. [expectation fulfill];
  630. }];
  631. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  632. // Wait a little bit so the server has enough time to respond.
  633. [self waitForExpectationsWithTimeout:10
  634. handler:^(NSError *error) {
  635. if (error) {
  636. XCTFail(@"Timeout Error: %@", error);
  637. }
  638. }];
  639. }
  640. - (void)testNilURLNSURLSession_GET_background {
  641. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  642. _statusCode = 200;
  643. [_network getURL:nil
  644. headers:nil
  645. queue:_backgroundQueue
  646. usingBackgroundSession:YES
  647. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  648. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  649. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  650. [expectation fulfill];
  651. }];
  652. [self waitForExpectationsWithTimeout:10
  653. handler:^(NSError *error) {
  654. if (error) {
  655. XCTFail(@"Timeout Error: %@", error);
  656. }
  657. }];
  658. }
  659. - (void)testEmptyURLNSURLSession_GET_background {
  660. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  661. _statusCode = 200;
  662. [_network getURL:[NSURL URLWithString:@""]
  663. headers:nil
  664. queue:_backgroundQueue
  665. usingBackgroundSession:YES
  666. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  667. XCTAssertEqual(error.code, GULErrorCodeNetworkInvalidURL);
  668. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  669. [expectation fulfill];
  670. }];
  671. [self waitForExpectationsWithTimeout:10
  672. handler:^(NSError *error) {
  673. if (error) {
  674. XCTFail(@"Timeout Error: %@", error);
  675. }
  676. }];
  677. }
  678. - (void)testNilQueueNSURLSession_GET_background {
  679. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  680. NSURL *url =
  681. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/1", _httpServer.port]];
  682. _statusCode = 200;
  683. [_network getURL:url
  684. headers:nil
  685. queue:nil
  686. usingBackgroundSession:YES
  687. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  688. XCTAssertNotNil(data);
  689. NSString *responseBody = [[NSString alloc] initWithData:data
  690. encoding:NSUTF8StringEncoding];
  691. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  692. XCTAssertNil(error);
  693. XCTAssertFalse(self->_network.hasUploadInProgress, "There must be no pending request");
  694. [expectation fulfill];
  695. }];
  696. XCTAssertTrue(self->_network.hasUploadInProgress, "There must be a pending request");
  697. // Wait a little bit so the server has enough time to respond.
  698. [self waitForExpectationsWithTimeout:10
  699. handler:^(NSError *error) {
  700. if (error) {
  701. XCTFail(@"Timeout Error: %@", error);
  702. }
  703. }];
  704. }
  705. - (void)testHasRequestPendingNSURLSession_GET_background {
  706. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  707. NSURL *url =
  708. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/hasRequestPending",
  709. _httpServer.port]];
  710. _statusCode = 200;
  711. [_network getURL:url
  712. headers:nil
  713. queue:_backgroundQueue
  714. usingBackgroundSession:YES
  715. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  716. XCTAssertNotNil(data);
  717. NSString *responseBody = [[NSString alloc] initWithData:data
  718. encoding:NSUTF8StringEncoding];
  719. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  720. XCTAssertNil(error);
  721. XCTAssertFalse(self->_network.hasUploadInProgress,
  722. @"hasUploadInProgress must be false");
  723. [expectation fulfill];
  724. }];
  725. XCTAssertTrue(self->_network.hasUploadInProgress, @"hasUploadInProgress must be true");
  726. // Wait a little bit so the server has enough time to respond.
  727. [self waitForExpectationsWithTimeout:10
  728. handler:^(NSError *error) {
  729. if (error) {
  730. XCTFail(@"Timeout Error: %@", error);
  731. }
  732. }];
  733. }
  734. - (void)testHeaders_background {
  735. XCTestExpectation *expectation = [self expectationWithDescription:@"Expect block is called"];
  736. NSURL *url =
  737. [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:%d/3", _httpServer.port]];
  738. _statusCode = 200;
  739. NSDictionary *headers = @{@"Version" : @"123"};
  740. [_network getURL:url
  741. headers:headers
  742. queue:_backgroundQueue
  743. usingBackgroundSession:YES
  744. completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
  745. XCTAssertNotNil(data);
  746. NSString *responseBody = [[NSString alloc] initWithData:data
  747. encoding:NSUTF8StringEncoding];
  748. XCTAssertEqualObjects(responseBody, @"<html><body>Hello, World!</body></html>");
  749. XCTAssertNil(error);
  750. NSString *version = [self->_request.allHeaderFieldValues valueForKey:@"Version"];
  751. XCTAssertEqualObjects(version, @"123");
  752. [expectation fulfill];
  753. }];
  754. // Wait a little bit so the server has enough time to respond.
  755. [self waitForExpectationsWithTimeout:10
  756. handler:^(NSError *error) {
  757. if (error) {
  758. XCTFail(@"Timeout Error: %@", error);
  759. }
  760. }];
  761. }
  762. #pragma mark - Test clean up files
  763. - (void)testRemoveExpiredFiles {
  764. NSError *writeError = nil;
  765. NSFileManager *fileManager = [NSFileManager defaultManager];
  766. GULNetworkURLSession *session = [[GULNetworkURLSession alloc]
  767. initWithNetworkLoggerDelegate:(id<GULNetworkLoggerDelegate>)_network];
  768. NSArray *paths =
  769. NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
  770. NSString *applicationSupportDirectory = paths.firstObject;
  771. NSArray *tempPathComponents = @[
  772. applicationSupportDirectory, kGULNetworkApplicationSupportSubdirectory,
  773. @"GULNetworkTemporaryDirectory"
  774. ];
  775. NSURL *folderURL = [NSURL fileURLWithPathComponents:tempPathComponents];
  776. [fileManager createDirectoryAtURL:folderURL
  777. withIntermediateDirectories:YES
  778. attributes:nil
  779. error:&writeError];
  780. NSURL *tempFile1 = [folderURL URLByAppendingPathComponent:@"FIRUpload_temp_123"];
  781. [self createTempFileAtURL:tempFile1];
  782. NSURL *tempFile2 = [folderURL URLByAppendingPathComponent:@"FIRUpload_temp_456"];
  783. [self createTempFileAtURL:tempFile2];
  784. XCTAssertTrue([fileManager fileExistsAtPath:tempFile1.path]);
  785. XCTAssertTrue([fileManager fileExistsAtPath:tempFile2.path]);
  786. NSDate *now =
  787. [[NSDate date] dateByAddingTimeInterval:1]; // Start mocking the clock to avoid flakiness.
  788. id mockDate = OCMStrictClassMock([NSDate class]);
  789. [[[mockDate stub] andReturn:now] date];
  790. // The file should not be removed since it is not expired yet.
  791. [session maybeRemoveTempFilesAtURL:folderURL expiringTime:20];
  792. XCTAssertTrue([fileManager fileExistsAtPath:tempFile1.path]);
  793. XCTAssertTrue([fileManager fileExistsAtPath:tempFile2.path]);
  794. [mockDate stopMocking];
  795. mockDate = nil;
  796. now = [[NSDate date] dateByAddingTimeInterval:100]; // Move forward in time 100s.
  797. mockDate = OCMStrictClassMock([NSDate class]);
  798. [[[mockDate stub] andReturn:now] date];
  799. [session maybeRemoveTempFilesAtURL:folderURL expiringTime:20];
  800. XCTAssertFalse([fileManager fileExistsAtPath:tempFile1.path]);
  801. XCTAssertFalse([fileManager fileExistsAtPath:tempFile2.path]);
  802. [mockDate stopMocking];
  803. mockDate = nil;
  804. }
  805. #pragma mark - Internal Methods
  806. - (void)createTempFileAtURL:(NSURL *)fileURL {
  807. // Create a dictionary and write it to file.
  808. NSDictionary *someContent = @{@"object" : @"key"};
  809. [someContent writeToURL:fileURL atomically:YES];
  810. }
  811. - (void)verifyResponse:(NSHTTPURLResponse *)response error:(NSError *)error {
  812. XCTAssertNil(error, @"Error is not expected");
  813. XCTAssertNotNil(response, @"Error is not expected");
  814. }
  815. - (void)verifyRequest {
  816. XCTAssertNotNil(_request, @"Request cannot be nil");
  817. // Test whether the request is compressed correctly.
  818. NSData *requestBody = [_request body];
  819. NSData *decompressedRequestData = [NSData gul_dataByInflatingGzippedData:requestBody error:NULL];
  820. NSString *requestString = [[NSString alloc] initWithData:decompressedRequestData
  821. encoding:NSUTF8StringEncoding];
  822. XCTAssertEqualObjects(requestString, @"Google", @"Request is not compressed correctly.");
  823. // The request has to be a POST.
  824. XCTAssertEqualObjects([_request method], @"POST", @"Request method has to be POST");
  825. // Content length has to be set correctly.
  826. NSString *contentLength = [_request.allHeaderFieldValues valueForKey:@"Content-Length"];
  827. XCTAssertEqualObjects(contentLength, @"26", @"Content Length is incorrect");
  828. NSString *contentEncoding = [_request.allHeaderFieldValues valueForKey:@"Content-Encoding"];
  829. XCTAssertEqualObjects(contentEncoding, @"gzip", @"Content Encoding is incorrect");
  830. }
  831. #pragma mark - Helper Methods
  832. - (GTMHTTPResponseMessage *)httpServer:(GTMHTTPServer *)server
  833. handleRequest:(GTMHTTPRequestMessage *)request {
  834. _request = request;
  835. NSData *html =
  836. [@"<html><body>Hello, World!</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
  837. return [GTMHTTPResponseMessage responseWithBody:html
  838. contentType:@"text/html; charset=UTF-8"
  839. statusCode:_statusCode];
  840. }
  841. - (BOOL)isReachable {
  842. return _fakeNetworkIsReachable;
  843. }
  844. - (GULReachabilityStatus)reachabilityStatus {
  845. return _fakeReachabilityStatus;
  846. }
  847. #pragma mark - FIRReachabilityDelegate
  848. - (void)reachabilityDidChange {
  849. _currentNetworkStatus = _fakeNetworkIsReachable;
  850. }
  851. @end