FPRNSURLSessionInstrumentTest.m 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  1. // Copyright 2020 Google LLC
  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. #pragma mark - Unswizzle based tests
  15. #ifndef SWIFT_PACKAGE
  16. #import "FirebasePerformance/Tests/Unit/Instruments/FPRNSURLSessionInstrumentTestDelegates.h"
  17. #import <XCTest/XCTest.h>
  18. #import <objc/runtime.h>
  19. #import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h"
  20. #import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h"
  21. #import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h"
  22. #import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h"
  23. #import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument_Private.h"
  24. #import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h"
  25. #import "FirebasePerformance/Tests/Unit/FPRTestCase.h"
  26. #import "FirebasePerformance/Tests/Unit/FPRTestUtils.h"
  27. #import "FirebasePerformance/Tests/Unit/Server/FPRHermeticTestServer.h"
  28. /** This class is used to wrap an NSURLSession object during testing. */
  29. @interface FPRNSURLSessionProxy : NSProxy {
  30. // The wrapped session object.
  31. id _session;
  32. }
  33. /** @return an instance of the session proxy. */
  34. - (instancetype)initWithSession:(id)session;
  35. @end
  36. @implementation FPRNSURLSessionProxy
  37. - (instancetype)initWithSession:(id)session {
  38. if (self) {
  39. _session = session;
  40. }
  41. return self;
  42. }
  43. - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
  44. return [_session methodSignatureForSelector:selector];
  45. }
  46. - (void)forwardInvocation:(NSInvocation *)invocation {
  47. [invocation invokeWithTarget:_session];
  48. }
  49. @end
  50. @interface FPRNSURLSessionDelegateProxy : NSProxy {
  51. // The wrapped delegate object.
  52. id _delegate;
  53. }
  54. /** @return an instance of the delegate proxy. */
  55. - (instancetype)initWithDelegate:(id)delegate;
  56. @end
  57. @implementation FPRNSURLSessionDelegateProxy
  58. - (instancetype)initWithDelegate:(id)delegate {
  59. if (self) {
  60. _delegate = delegate;
  61. }
  62. return self;
  63. }
  64. - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
  65. return [_delegate methodSignatureForSelector:selector];
  66. }
  67. - (BOOL)respondsToSelector:(SEL)aSelector {
  68. return [_delegate respondsToSelector:aSelector];
  69. }
  70. - (void)forwardInvocation:(NSInvocation *)invocation {
  71. [invocation invokeWithTarget:_delegate];
  72. }
  73. @end
  74. @interface FPRNSURLSessionInstrumentTest : FPRTestCase
  75. /** Test server to create connections to. */
  76. @property(nonatomic) FPRHermeticTestServer *testServer;
  77. @end
  78. @implementation FPRNSURLSessionInstrumentTest
  79. - (void)setUp {
  80. [super setUp];
  81. FIRPerformance *performance = [FIRPerformance sharedInstance];
  82. [performance setDataCollectionEnabled:YES];
  83. XCTAssertFalse(self.testServer.isRunning);
  84. self.testServer = [[FPRHermeticTestServer alloc] init];
  85. [self.testServer registerTestPaths];
  86. [self.testServer start];
  87. }
  88. - (void)tearDown {
  89. [super tearDown];
  90. FIRPerformance *performance = [FIRPerformance sharedInstance];
  91. [performance setDataCollectionEnabled:NO];
  92. [self.testServer stop];
  93. [FPRConfigurations reset];
  94. }
  95. /** Waits for the server connection to finish by giving a block to run just before a response is
  96. * sent.
  97. *
  98. * @param block A block to run just after the server response is sent.
  99. */
  100. - (void)waitAndRunBlockAfterResponse:(void (^)(id self,
  101. GCDWebServerRequest *_Nonnull request,
  102. GCDWebServerResponse *_Nonnull response))block {
  103. __block BOOL loopingMainThread = YES;
  104. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  105. dispatch_semaphore_t sema = dispatch_semaphore_create(0);
  106. __weak id weakSelf = self;
  107. self.testServer.responseCompletedBlock =
  108. ^(GCDWebServerRequest *_Nonnull request, GCDWebServerResponse *_Nonnull response) {
  109. block(weakSelf, request, response);
  110. dispatch_semaphore_signal(sema);
  111. };
  112. XCTAssertEqual(
  113. dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC)), 0);
  114. loopingMainThread = NO;
  115. });
  116. // This is necessary because the FPRHermeticTestServer callbacks occur on the main thread.
  117. while (loopingMainThread) {
  118. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
  119. }
  120. }
  121. #pragma mark - Testing infrastructure and subclass instrumenting
  122. /** Tests initing of FPRNSURLSessionInstrument also inits NSURLSessionDelegate instrument. */
  123. - (void)testInit {
  124. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  125. [instrument registerInstrumentors];
  126. self.testServer.responseCompletedBlock =
  127. ^(GCDWebServerRequest *_Nonnull request, GCDWebServerResponse *_Nonnull response) {
  128. XCTAssert(instrument);
  129. XCTAssert(instrument.delegateInstrument);
  130. };
  131. [instrument deregisterInstrumentors];
  132. }
  133. /** Tests that creating a shared session returns a non-nil object. */
  134. - (void)testSharedSession {
  135. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  136. [instrument registerInstrumentors];
  137. NSURLSession *session = [NSURLSession sharedSession];
  138. XCTAssertNotNil(session);
  139. [instrument deregisterInstrumentors];
  140. }
  141. /** Tests that a method that returns an NSURLSession subclass registers that subclass. */
  142. - (void)testSubclassRegistration {
  143. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  144. [instrument registerInstrumentors];
  145. NSURLSession *session = [NSURLSession sharedSession];
  146. XCTAssertNotNil(session);
  147. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  148. [instrument deregisterInstrumentors];
  149. }
  150. /** Tests that a discovered subclass isn't registered more than once. */
  151. - (void)testSubclassIsNotRegisteredMoreThanOnce {
  152. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  153. [instrument registerInstrumentors];
  154. NSURLSession *session = [NSURLSession sharedSession];
  155. NSURLSession *session2 = [NSURLSession sharedSession];
  156. XCTAssertNotNil(session);
  157. XCTAssertNotNil(session2);
  158. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  159. [instrument deregisterInstrumentors];
  160. }
  161. /** Tests sessionWithConfiguration: with the default configuration returns a non-nil object. */
  162. - (void)testSessionWithDefaultSessionConfiguration {
  163. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  164. [instrument registerInstrumentors];
  165. NSURLSessionConfiguration *configuration =
  166. [NSURLSessionConfiguration defaultSessionConfiguration];
  167. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  168. XCTAssertNotNil(session);
  169. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  170. [instrument deregisterInstrumentors];
  171. }
  172. /** Tests sessionWithConfiguration: with an ephemeral configuration returns a non-nil object. */
  173. - (void)testSessionWithEphemeralSessionConfiguration {
  174. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  175. [instrument registerInstrumentors];
  176. NSURLSessionConfiguration *configuration =
  177. [NSURLSessionConfiguration ephemeralSessionConfiguration];
  178. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  179. XCTAssertNotNil(session);
  180. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  181. [instrument deregisterInstrumentors];
  182. }
  183. /** Tests sessionWithConfiguration: with a background configuration returns a non-nil object. */
  184. - (void)testSessionWithBackgroundSessionConfiguration {
  185. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  186. [instrument registerInstrumentors];
  187. NSURLSessionConfiguration *configuration =
  188. [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"madeUpID"];
  189. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  190. XCTAssertNotNil(session);
  191. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  192. [instrument deregisterInstrumentors];
  193. }
  194. /** Tests instrumenting an NSProxy wrapped NSURLSession object works. */
  195. - (void)testProxyWrappedSharedSession {
  196. Method method = class_getClassMethod([NSURLSession class], @selector(sharedSession));
  197. IMP originalImp = method_getImplementation(method);
  198. IMP swizzledImp = imp_implementationWithBlock(^(id session) {
  199. typedef NSURLSession *(*OriginalImp)(id, SEL);
  200. NSURLSession *originalSession = ((OriginalImp)originalImp)(session, @selector(sharedSession));
  201. return [[FPRNSURLSessionProxy alloc] initWithSession:originalSession];
  202. });
  203. method_setImplementation(method, swizzledImp);
  204. XCTAssertEqual([[NSURLSession sharedSession] class], [FPRNSURLSessionProxy class]);
  205. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  206. [instrument registerInstrumentors];
  207. NSURLSession *session;
  208. XCTAssertNoThrow(session = [NSURLSession sharedSession]);
  209. NSURL *url = self.testServer.serverURL;
  210. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler"];
  211. NSURLSessionDownloadTask *task =
  212. [session downloadTaskWithURL:url
  213. completionHandler:^(NSURL *_Nullable location, NSURLResponse *_Nullable response,
  214. NSError *_Nullable error) {
  215. [expectation fulfill];
  216. }];
  217. [task resume];
  218. XCTAssertNotNil(task);
  219. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  220. [instrument deregisterInstrumentors];
  221. method_setImplementation(method, originalImp);
  222. XCTAssertNotEqual([[NSURLSession sharedSession] class], [FPRNSURLSessionProxy class]);
  223. }
  224. /** Tests instrumenting an NSProxy wrapped NSURLSession object works. */
  225. - (void)testProxyWrappedSessionWithConfiguration {
  226. Method method = class_getClassMethod([NSURLSession class], @selector(sessionWithConfiguration:));
  227. IMP originalImp = method_getImplementation(method);
  228. IMP swizzledImp =
  229. imp_implementationWithBlock(^(id session, NSURLSessionConfiguration *configuration) {
  230. typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *);
  231. NSURLSession *originalSession = ((OriginalImp)originalImp)(
  232. session, @selector(sessionWithConfiguration:), configuration);
  233. return [[FPRNSURLSessionProxy alloc] initWithSession:originalSession];
  234. });
  235. method_setImplementation(method, swizzledImp);
  236. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
  237. XCTAssertEqual([[NSURLSession sessionWithConfiguration:config] class],
  238. [FPRNSURLSessionProxy class]);
  239. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  240. [instrument registerInstrumentors];
  241. NSURLSession *session;
  242. XCTAssertNoThrow(session = [NSURLSession sessionWithConfiguration:config]);
  243. NSURL *url = self.testServer.serverURL;
  244. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler"];
  245. NSURLSessionDownloadTask *task =
  246. [session downloadTaskWithURL:url
  247. completionHandler:^(NSURL *_Nullable location, NSURLResponse *_Nullable response,
  248. NSError *_Nullable error) {
  249. [expectation fulfill];
  250. }];
  251. XCTAssertNotNil(task);
  252. [task resume];
  253. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  254. [instrument deregisterInstrumentors];
  255. method_setImplementation(method, originalImp);
  256. XCTAssertNotEqual([[NSURLSession sharedSession] class], [FPRNSURLSessionProxy class]);
  257. }
  258. /** Tests instrumenting an NSProxy wrapped NSURLSession object works. */
  259. - (void)testProxyWrappedSessionWithConfigurationDelegateDelegateQueue {
  260. SEL selector = @selector(sessionWithConfiguration:delegate:delegateQueue:);
  261. Method method = class_getClassMethod([NSURLSession class], selector);
  262. IMP originalImp = method_getImplementation(method);
  263. IMP swizzledImp = imp_implementationWithBlock(
  264. ^(id session, NSURLSessionConfiguration *configuration, id<NSURLSessionDelegate> *delegate,
  265. NSOperationQueue *delegateQueue) {
  266. typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *,
  267. id<NSURLSessionDelegate> *, NSOperationQueue *);
  268. NSURLSession *originalSession =
  269. ((OriginalImp)originalImp)(session, selector, configuration, delegate, delegateQueue);
  270. return [[FPRNSURLSessionProxy alloc] initWithSession:originalSession];
  271. });
  272. method_setImplementation(method, swizzledImp);
  273. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
  274. XCTAssertEqual([[NSURLSession sessionWithConfiguration:config delegate:nil
  275. delegateQueue:nil] class],
  276. [FPRNSURLSessionProxy class]);
  277. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  278. [instrument registerInstrumentors];
  279. NSURLSession *session;
  280. XCTAssertNoThrow(session = [NSURLSession sessionWithConfiguration:config
  281. delegate:nil
  282. delegateQueue:nil]);
  283. NSURL *url = self.testServer.serverURL;
  284. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler"];
  285. NSURLSessionDownloadTask *task =
  286. [session downloadTaskWithURL:url
  287. completionHandler:^(NSURL *_Nullable location, NSURLResponse *_Nullable response,
  288. NSError *_Nullable error) {
  289. [expectation fulfill];
  290. }];
  291. XCTAssertNotNil(task);
  292. [task resume];
  293. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  294. [instrument deregisterInstrumentors];
  295. method_setImplementation(method, originalImp);
  296. }
  297. #pragma mark - Testing delegate method wrapping
  298. /** Tests using a nil delegate still results in tracking responses. */
  299. - (void)testSessionWithConfigurationDelegateDelegateQueueWithNilDelegate {
  300. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  301. [instrument registerInstrumentors];
  302. NSURLSessionConfiguration *configuration =
  303. [NSURLSessionConfiguration defaultSessionConfiguration];
  304. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  305. delegate:nil
  306. delegateQueue:nil];
  307. NSURLRequest *request = [NSURLRequest requestWithURL:self.testServer.serverURL];
  308. NSURLSessionTask *task;
  309. @autoreleasepool {
  310. task = [session dataTaskWithRequest:request];
  311. XCTAssertNotNil(task);
  312. [task resume];
  313. XCTAssertNotNil(session.delegate); // Not sure this is the desired behavior.
  314. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  315. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  316. GCDWebServerResponse *_Nonnull response) {
  317. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:task]);
  318. }];
  319. }
  320. [instrument deregisterInstrumentors];
  321. }
  322. /** Tests that the delegate class isn't instrumented more than once. */
  323. - (void)testDelegateClassOnlyRegisteredOnce {
  324. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  325. [instrument registerInstrumentors];
  326. FPRNSURLSessionCompleteTestDelegate *delegate =
  327. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  328. NSURLSessionConfiguration *configuration =
  329. [NSURLSessionConfiguration defaultSessionConfiguration];
  330. [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:nil];
  331. [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:nil];
  332. XCTAssertEqual(instrument.delegateInstrument.classInstrumentors.count, 1);
  333. XCTAssertEqual(instrument.delegateInstrument.instrumentedClasses.count, 1);
  334. [instrument deregisterInstrumentors];
  335. }
  336. /** Tests that the called delegate selector is wrapped and calls through. */
  337. - (void)testDelegateURLSessionTaskDidCompleteWithError {
  338. [self.testServer stop];
  339. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  340. [instrument registerInstrumentors];
  341. FPRNSURLSessionCompleteTestDelegate *delegate =
  342. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  343. // This request needs to fail.
  344. NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://nonurl"]];
  345. NSURLSessionConfiguration *configuration =
  346. [NSURLSessionConfiguration defaultSessionConfiguration];
  347. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  348. delegate:delegate
  349. delegateQueue:nil];
  350. NSURLSessionTask *task;
  351. @autoreleasepool {
  352. task = [session dataTaskWithRequest:request];
  353. [task resume];
  354. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  355. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
  356. }
  357. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:task]);
  358. XCTAssertTrue(delegate.URLSessionTaskDidCompleteWithErrorCalled);
  359. [instrument deregisterInstrumentors];
  360. [self.testServer start];
  361. }
  362. /** Tests that the called delegate selector is wrapped and calls through. */
  363. - (void)testDelegateURLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedToSend {
  364. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  365. [instrument registerInstrumentors];
  366. FPRNSURLSessionCompleteTestDelegate *delegate =
  367. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  368. NSURLSessionConfiguration *configuration =
  369. [NSURLSessionConfiguration defaultSessionConfiguration];
  370. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  371. delegate:delegate
  372. delegateQueue:nil];
  373. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  374. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  375. request.HTTPMethod = @"POST";
  376. NSBundle *bundle = [FPRTestUtils getBundle];
  377. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  378. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:fileURL];
  379. [uploadTask resume];
  380. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  381. FPRNetworkTrace *networkTrace = [FPRNetworkTrace networkTraceFromObject:uploadTask];
  382. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  383. GCDWebServerResponse *_Nonnull response) {
  384. XCTAssertTrue(delegate.URLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedCalled);
  385. XCTAssert(networkTrace.requestSize > 0);
  386. XCTAssert(
  387. [networkTrace
  388. timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
  389. andState:FPRNetworkTraceCheckpointStateRequestCompleted] > 0);
  390. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  391. }];
  392. [instrument deregisterInstrumentors];
  393. }
  394. /** Tests that the called delegate selector is wrapped and calls through. */
  395. - (void)testDelegateURLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler {
  396. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  397. [instrument registerInstrumentors];
  398. FPRNSURLSessionCompleteTestDelegate *delegate =
  399. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  400. NSURLSessionConfiguration *configuration =
  401. [NSURLSessionConfiguration defaultSessionConfiguration];
  402. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testRedirect"];
  403. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  404. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  405. delegate:delegate
  406. delegateQueue:nil];
  407. NSURLSessionTask *task = [session dataTaskWithRequest:request];
  408. [task resume];
  409. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  410. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  411. GCDWebServerResponse *_Nonnull response) {
  412. XCTAssertTrue(
  413. delegate.URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandlerCalled);
  414. }];
  415. [instrument deregisterInstrumentors];
  416. }
  417. /** Tests that the called delegate selector is wrapped and calls through. */
  418. - (void)testDelegateURLSessionDataTaskDidReceiveData {
  419. FPRNSURLSessionInstrument *instrument;
  420. NSURLSessionDataTask *dataTask;
  421. @autoreleasepool {
  422. instrument = [[FPRNSURLSessionInstrument alloc] init];
  423. [instrument registerInstrumentors];
  424. FPRNSURLSessionCompleteTestDelegate *delegate =
  425. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  426. NSURLSessionConfiguration *configuration =
  427. [NSURLSessionConfiguration defaultSessionConfiguration];
  428. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  429. delegate:delegate
  430. delegateQueue:nil];
  431. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  432. dataTask = [session dataTaskWithURL:URL];
  433. [dataTask resume];
  434. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  435. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  436. GCDWebServerResponse *_Nonnull response) {
  437. XCTAssertTrue(delegate.URLSessionDataTaskDidReceiveDataCalled);
  438. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  439. }];
  440. }
  441. [instrument deregisterInstrumentors];
  442. }
  443. /** Tests that the called delegate selector is wrapped and calls through. */
  444. - (void)testDelegateURLSessionDownloadTaskDidFinishDownloadingToURL {
  445. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  446. [instrument registerInstrumentors];
  447. FPRNSURLSessionCompleteTestDelegate *delegate =
  448. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  449. NSURLSessionConfiguration *configuration =
  450. [NSURLSessionConfiguration defaultSessionConfiguration];
  451. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  452. delegate:delegate
  453. delegateQueue:nil];
  454. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  455. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  456. [downloadTask resume];
  457. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  458. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  459. GCDWebServerResponse *_Nonnull response) {
  460. XCTAssertTrue(delegate.URLSessionDownloadTaskDidFinishDownloadingToURLCalled);
  461. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  462. }];
  463. [instrument deregisterInstrumentors];
  464. }
  465. /** Tests that the called delegate selector is wrapped and calls through. */
  466. - (void)testDelegateURLSessionDownloadDidReceiveResponseCompletionHandler {
  467. FPRNSURLSessionInstrument *instrument;
  468. NSURLSessionDataTask *dataTask;
  469. @autoreleasepool {
  470. instrument = [[FPRNSURLSessionInstrument alloc] init];
  471. [instrument registerInstrumentors];
  472. FPRNSURLSessionCompleteTestDelegate *delegate =
  473. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  474. NSURLSessionConfiguration *configuration =
  475. [NSURLSessionConfiguration defaultSessionConfiguration];
  476. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  477. delegate:delegate
  478. delegateQueue:nil];
  479. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  480. dataTask = [session dataTaskWithURL:URL];
  481. [dataTask resume];
  482. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  483. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  484. GCDWebServerResponse *_Nonnull response) {
  485. XCTAssertTrue(delegate.URLSessionDataTaskDidReceiveResponseCompletionHandlerCalled);
  486. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  487. }];
  488. }
  489. [instrument deregisterInstrumentors];
  490. }
  491. /** Tests that the called delegate selector is wrapped and calls through. */
  492. - (void)testDelegateURLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytes {
  493. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  494. [instrument registerInstrumentors];
  495. FPRNSURLSessionTestDownloadDelegate *delegate =
  496. [[FPRNSURLSessionTestDownloadDelegate alloc] init];
  497. NSURLSessionConfiguration *configuration =
  498. [NSURLSessionConfiguration defaultSessionConfiguration];
  499. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  500. delegate:delegate
  501. delegateQueue:nil];
  502. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  503. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  504. [downloadTask resume];
  505. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
  506. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  507. XCTAssertTrue(delegate.URLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytesCalled);
  508. [instrument deregisterInstrumentors];
  509. }
  510. /** Tests that the called delegate selector is wrapped and calls through. */
  511. - (void)testDelegateURLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesExpectedToWrite {
  512. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  513. [instrument registerInstrumentors];
  514. FPRNSURLSessionCompleteTestDelegate *delegate =
  515. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  516. NSURLSessionConfiguration *configuration =
  517. [NSURLSessionConfiguration defaultSessionConfiguration];
  518. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  519. delegate:delegate
  520. delegateQueue:nil];
  521. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  522. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  523. [downloadTask resume];
  524. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  525. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  526. GCDWebServerResponse *_Nonnull response) {
  527. XCTAssertTrue(delegate.URLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesCalled);
  528. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
  529. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  530. }];
  531. [instrument deregisterInstrumentors];
  532. }
  533. /** Tests that even if a delegate doesn't implement a method, we add it to the delegate class. */
  534. - (void)testDelegateUnimplementedURLSessionTaskDidCompleteWithError {
  535. FPRNSURLSessionTestDelegate *delegate = [[FPRNSURLSessionTestDelegate alloc] init];
  536. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  537. [instrument registerInstrumentors];
  538. NSURLSessionConfiguration *configuration =
  539. [NSURLSessionConfiguration defaultSessionConfiguration];
  540. XCTAssertFalse([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]);
  541. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  542. delegate:delegate
  543. delegateQueue:nil];
  544. XCTAssertTrue([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]);
  545. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:self.testServer.serverURL];
  546. [downloadTask resume];
  547. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  548. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  549. GCDWebServerResponse *_Nonnull response) {
  550. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  551. }];
  552. [instrument deregisterInstrumentors];
  553. }
  554. #pragma mark - Testing proxy delegate method wrapping
  555. /** Tests that the delegate class is instrumented once when its wrapped with NSProxy. */
  556. - (void)testProxyDelegateSwizzlesDelegateOnce {
  557. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  558. [instrument registerInstrumentors];
  559. FPRNSURLSessionCompleteTestDelegate *delegate =
  560. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  561. FPRNSURLSessionDelegateProxy *proxyDelegate =
  562. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  563. NSURLSessionConfiguration *configuration =
  564. [NSURLSessionConfiguration defaultSessionConfiguration];
  565. [NSURLSession sessionWithConfiguration:configuration delegate:proxyDelegate delegateQueue:nil];
  566. [NSURLSession sessionWithConfiguration:configuration delegate:proxyDelegate delegateQueue:nil];
  567. XCTAssertEqual(instrument.delegateInstrument.classInstrumentors.count, 1);
  568. XCTAssertEqual(instrument.delegateInstrument.instrumentedClasses.count, 1);
  569. XCTAssertTrue(
  570. [instrument.delegateInstrument.instrumentedClasses containsObject:[delegate class]]);
  571. [instrument deregisterInstrumentors];
  572. }
  573. /** Tests that the called delegate selector is wrapped and calls through. */
  574. - (void)testProxyDelegateURLSessionTaskDidCompleteWithError {
  575. [self.testServer stop];
  576. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  577. [instrument registerInstrumentors];
  578. FPRNSURLSessionCompleteTestDelegate *delegate =
  579. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  580. FPRNSURLSessionDelegateProxy *proxyDelegate =
  581. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  582. // This request needs to fail.
  583. NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://nonurl"]];
  584. NSURLSessionConfiguration *configuration =
  585. [NSURLSessionConfiguration defaultSessionConfiguration];
  586. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  587. delegate:proxyDelegate
  588. delegateQueue:nil];
  589. NSURLSessionTask *task;
  590. @autoreleasepool {
  591. task = [session dataTaskWithRequest:request];
  592. [task resume];
  593. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  594. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
  595. }
  596. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:task]);
  597. XCTAssertTrue(delegate.URLSessionTaskDidCompleteWithErrorCalled);
  598. [instrument deregisterInstrumentors];
  599. [self.testServer start];
  600. }
  601. /** Tests that the called delegate selector is wrapped and calls through. */
  602. - (void)testProxyDelegateURLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedToSend {
  603. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  604. [instrument registerInstrumentors];
  605. FPRNSURLSessionCompleteTestDelegate *delegate =
  606. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  607. FPRNSURLSessionDelegateProxy *proxyDelegate =
  608. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  609. NSURLSessionConfiguration *configuration =
  610. [NSURLSessionConfiguration defaultSessionConfiguration];
  611. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  612. delegate:proxyDelegate
  613. delegateQueue:nil];
  614. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  615. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  616. request.HTTPMethod = @"POST";
  617. NSBundle *bundle = [FPRTestUtils getBundle];
  618. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  619. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:fileURL];
  620. [uploadTask resume];
  621. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  622. FPRNetworkTrace *networkTrace = [FPRNetworkTrace networkTraceFromObject:uploadTask];
  623. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  624. GCDWebServerResponse *_Nonnull response) {
  625. XCTAssertTrue(delegate.URLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedCalled);
  626. XCTAssert(networkTrace.requestSize > 0);
  627. XCTAssert(
  628. [networkTrace
  629. timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
  630. andState:FPRNetworkTraceCheckpointStateRequestCompleted] > 0);
  631. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  632. }];
  633. [instrument deregisterInstrumentors];
  634. }
  635. /** Tests that the called delegate selector is wrapped and calls through. */
  636. - (void)testProxyDelegateURLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler {
  637. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  638. [instrument registerInstrumentors];
  639. FPRNSURLSessionCompleteTestDelegate *delegate =
  640. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  641. FPRNSURLSessionDelegateProxy *proxyDelegate =
  642. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  643. NSURLSessionConfiguration *configuration =
  644. [NSURLSessionConfiguration defaultSessionConfiguration];
  645. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testRedirect"];
  646. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  647. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  648. delegate:proxyDelegate
  649. delegateQueue:nil];
  650. NSURLSessionTask *task = [session dataTaskWithRequest:request];
  651. [task resume];
  652. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  653. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  654. GCDWebServerResponse *_Nonnull response) {
  655. XCTAssertTrue(
  656. delegate.URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandlerCalled);
  657. }];
  658. [instrument deregisterInstrumentors];
  659. }
  660. /** Tests that the called delegate selector is wrapped and calls through. */
  661. - (void)testProxyDelegateURLSessionDataTaskDidReceiveData {
  662. FPRNSURLSessionInstrument *instrument;
  663. NSURLSessionDataTask *dataTask;
  664. @autoreleasepool {
  665. instrument = [[FPRNSURLSessionInstrument alloc] init];
  666. [instrument registerInstrumentors];
  667. FPRNSURLSessionCompleteTestDelegate *delegate =
  668. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  669. FPRNSURLSessionDelegateProxy *proxyDelegate =
  670. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  671. NSURLSessionConfiguration *configuration =
  672. [NSURLSessionConfiguration defaultSessionConfiguration];
  673. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  674. delegate:proxyDelegate
  675. delegateQueue:nil];
  676. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  677. dataTask = [session dataTaskWithURL:URL];
  678. [dataTask resume];
  679. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  680. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  681. GCDWebServerResponse *_Nonnull response) {
  682. XCTAssertTrue(delegate.URLSessionDataTaskDidReceiveDataCalled);
  683. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  684. }];
  685. }
  686. [instrument deregisterInstrumentors];
  687. }
  688. /** Tests that the called delegate selector is wrapped and calls through. */
  689. - (void)testProxyDelegateURLSessionDownloadTaskDidFinishDownloadingToURL {
  690. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  691. [instrument registerInstrumentors];
  692. FPRNSURLSessionCompleteTestDelegate *delegate =
  693. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  694. FPRNSURLSessionDelegateProxy *proxyDelegate =
  695. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  696. NSURLSessionConfiguration *configuration =
  697. [NSURLSessionConfiguration defaultSessionConfiguration];
  698. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  699. delegate:proxyDelegate
  700. delegateQueue:nil];
  701. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  702. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  703. [downloadTask resume];
  704. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  705. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  706. GCDWebServerResponse *_Nonnull response) {
  707. XCTAssertTrue(delegate.URLSessionDownloadTaskDidFinishDownloadingToURLCalled);
  708. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  709. }];
  710. [instrument deregisterInstrumentors];
  711. }
  712. /** Tests that the called delegate selector is wrapped and calls through. */
  713. - (void)testProxyDelegateURLSessionDownloadDidReceiveResponseCompletionHandler {
  714. FPRNSURLSessionInstrument *instrument;
  715. NSURLSessionDataTask *dataTask;
  716. @autoreleasepool {
  717. instrument = [[FPRNSURLSessionInstrument alloc] init];
  718. [instrument registerInstrumentors];
  719. FPRNSURLSessionCompleteTestDelegate *delegate =
  720. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  721. FPRNSURLSessionDelegateProxy *proxyDelegate =
  722. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  723. NSURLSessionConfiguration *configuration =
  724. [NSURLSessionConfiguration defaultSessionConfiguration];
  725. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  726. delegate:proxyDelegate
  727. delegateQueue:nil];
  728. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  729. dataTask = [session dataTaskWithURL:URL];
  730. [dataTask resume];
  731. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  732. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  733. GCDWebServerResponse *_Nonnull response) {
  734. XCTAssertTrue(delegate.URLSessionDataTaskDidReceiveResponseCompletionHandlerCalled);
  735. XCTAssertTrue(delegate.URLSessionTaskDidCompleteWithErrorCalled);
  736. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  737. }];
  738. }
  739. [instrument deregisterInstrumentors];
  740. }
  741. /** Tests that the called delegate selector is wrapped and calls through. */
  742. - (void)testProxyDelegateURLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytes {
  743. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  744. [instrument registerInstrumentors];
  745. FPRNSURLSessionTestDownloadDelegate *delegate =
  746. [[FPRNSURLSessionTestDownloadDelegate alloc] init];
  747. FPRNSURLSessionDelegateProxy *proxyDelegate =
  748. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  749. NSURLSessionConfiguration *configuration =
  750. [NSURLSessionConfiguration defaultSessionConfiguration];
  751. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  752. delegate:proxyDelegate
  753. delegateQueue:nil];
  754. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  755. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  756. [downloadTask resume];
  757. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
  758. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  759. XCTAssertTrue(delegate.URLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytesCalled);
  760. [instrument deregisterInstrumentors];
  761. }
  762. /** Tests that the called delegate selector is wrapped and calls through. */
  763. - (void)
  764. testProxyDelegateURLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesExpectedToWrite {
  765. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  766. [instrument registerInstrumentors];
  767. FPRNSURLSessionCompleteTestDelegate *delegate =
  768. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  769. FPRNSURLSessionDelegateProxy *proxyDelegate =
  770. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  771. NSURLSessionConfiguration *configuration =
  772. [NSURLSessionConfiguration defaultSessionConfiguration];
  773. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  774. delegate:proxyDelegate
  775. delegateQueue:nil];
  776. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  777. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  778. [downloadTask resume];
  779. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  780. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  781. GCDWebServerResponse *_Nonnull response) {
  782. XCTAssertTrue(delegate.URLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesCalled);
  783. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
  784. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  785. }];
  786. [instrument deregisterInstrumentors];
  787. }
  788. /** Tests that even if a delegate doesn't implement a method, we add it to the delegate class. */
  789. - (void)testProxyDelegateUnimplementedURLSessionTaskDidCompleteWithError {
  790. FPRNSURLSessionTestDelegate *delegate = [[FPRNSURLSessionTestDelegate alloc] init];
  791. FPRNSURLSessionDelegateProxy *proxyDelegate =
  792. [[FPRNSURLSessionDelegateProxy alloc] initWithDelegate:delegate];
  793. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  794. [instrument registerInstrumentors];
  795. NSURLSessionConfiguration *configuration =
  796. [NSURLSessionConfiguration defaultSessionConfiguration];
  797. XCTAssertFalse([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]);
  798. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  799. delegate:proxyDelegate
  800. delegateQueue:nil];
  801. XCTAssertTrue([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]);
  802. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:self.testServer.serverURL];
  803. [downloadTask resume];
  804. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  805. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  806. GCDWebServerResponse *_Nonnull response) {
  807. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  808. }];
  809. [instrument deregisterInstrumentors];
  810. }
  811. #pragma mark - Testing instance method wrapping
  812. /** Tests that dataTaskWithRequest: returns a non-nil object. */
  813. - (void)testDataTaskWithRequest {
  814. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  815. [instrument registerInstrumentors];
  816. NSURLSession *session = [NSURLSession sharedSession];
  817. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  818. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  819. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
  820. XCTAssertNotNil(dataTask);
  821. [dataTask resume];
  822. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  823. [instrument deregisterInstrumentors];
  824. }
  825. /** Tests that dataTaskWithRequest:completionHandler: returns a non-nil object. */
  826. - (void)testDataTaskWithRequestAndCompletionHandler {
  827. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  828. [instrument registerInstrumentors];
  829. NSURLSession *session = [NSURLSession sharedSession];
  830. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  831. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  832. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  833. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  834. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  835. [expectation fulfill];
  836. };
  837. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
  838. completionHandler:completionHandler];
  839. XCTAssertNotNil(dataTask);
  840. [dataTask resume];
  841. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  842. [instrument deregisterInstrumentors];
  843. }
  844. /** Tests that dataTaskWithRequest:completionHandler: for a POST request returns a non-nil object
  845. * and collects request size. */
  846. - (void)testDataTaskWithPostRequestAndCompletionHandler {
  847. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  848. [instrument registerInstrumentors];
  849. NSURLSession *session = [NSURLSession sharedSession];
  850. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  851. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  852. request.HTTPMethod = @"POST";
  853. request.HTTPBody = [@"sampleData" dataUsingEncoding:NSUTF8StringEncoding];
  854. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  855. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  856. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  857. [expectation fulfill];
  858. };
  859. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
  860. completionHandler:completionHandler];
  861. XCTAssertNotNil(dataTask);
  862. [dataTask resume];
  863. FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:dataTask];
  864. XCTAssertEqual(trace.requestSize, 10);
  865. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  866. [instrument deregisterInstrumentors];
  867. }
  868. /** Tests that dataTaskWithUrl:completionHandler: returns a non-nil object. */
  869. - (void)testDataTaskWithUrlAndCompletionHandler {
  870. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  871. [instrument registerInstrumentors];
  872. NSURLSession *session = [NSURLSession sharedSession];
  873. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  874. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  875. NSURLSessionDataTask *dataTask = nil;
  876. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  877. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  878. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  879. [expectation fulfill];
  880. };
  881. dataTask = [session dataTaskWithURL:URL completionHandler:completionHandler];
  882. XCTAssertNotNil(dataTask);
  883. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  884. [dataTask resume];
  885. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  886. [instrument deregisterInstrumentors];
  887. }
  888. /** Tests that uploadTaskWithRequest:fromFile: returns a non-nil object. */
  889. - (void)testUploadTaskWithRequestFromFile {
  890. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  891. [instrument registerInstrumentors];
  892. NSURLSession *session = [NSURLSession sharedSession];
  893. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  894. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  895. NSBundle *bundle = [FPRTestUtils getBundle];
  896. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  897. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:fileURL];
  898. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  899. XCTAssertNotNil(uploadTask);
  900. [uploadTask resume];
  901. [instrument deregisterInstrumentors];
  902. }
  903. /** Tests that uploadTaskWithRequest:fromFile:completionHandler returns a non-nil object. */
  904. - (void)testUploadTaskWithRequestFromFileCompletionHandler {
  905. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  906. [instrument registerInstrumentors];
  907. NSURLSession *session = [NSURLSession sharedSession];
  908. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  909. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  910. NSBundle *bundle = [FPRTestUtils getBundle];
  911. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  912. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  913. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  914. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  915. [expectation fulfill];
  916. };
  917. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
  918. fromFile:fileURL
  919. completionHandler:completionHandler];
  920. XCTAssertNotNil(uploadTask);
  921. [uploadTask resume];
  922. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  923. [instrument deregisterInstrumentors];
  924. }
  925. /** Tests that uploadTaskWithRequest:fromData: returns a non-nil object. */
  926. - (void)testUploadTaskWithRequestFromData {
  927. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  928. [instrument registerInstrumentors];
  929. NSURLSession *session = [NSURLSession sharedSession];
  930. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  931. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  932. request.HTTPMethod = @"POST";
  933. NSData *data = [[NSData alloc] init];
  934. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data];
  935. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  936. XCTAssertNotNil(uploadTask);
  937. [uploadTask resume];
  938. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  939. GCDWebServerResponse *_Nonnull response) {
  940. XCTAssertEqual(response.statusCode, 200);
  941. [instrument deregisterInstrumentors];
  942. }];
  943. }
  944. /** Tests that uploadTaskWithRequest:fromData:completionHandler: returns a non-nil object. */
  945. - (void)testUploadTaskWithRequestFromDataCompletionHandler {
  946. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  947. [instrument registerInstrumentors];
  948. NSURLSession *session = [NSURLSession sharedSession];
  949. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  950. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  951. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  952. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  953. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  954. [expectation fulfill];
  955. };
  956. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
  957. fromData:[[NSData alloc] init]
  958. completionHandler:completionHandler];
  959. XCTAssertNotNil(uploadTask);
  960. [uploadTask resume];
  961. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  962. [instrument deregisterInstrumentors];
  963. }
  964. /** Tests that uploadTaskWithStreamedRequest: returns a non-nil object. */
  965. - (void)testUploadTaskWithStreamedRequest {
  966. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  967. [instrument registerInstrumentors];
  968. NSURLSession *session = [NSURLSession sharedSession];
  969. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  970. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  971. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithStreamedRequest:request];
  972. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  973. XCTAssertNotNil(uploadTask);
  974. [uploadTask resume];
  975. [instrument deregisterInstrumentors];
  976. }
  977. /** Tests that downloadTaskWithRequest: returns a non-nil object. */
  978. - (void)testDownloadTaskWithRequest {
  979. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  980. [instrument registerInstrumentors];
  981. NSURLSession *session = [NSURLSession sharedSession];
  982. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  983. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  984. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
  985. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  986. XCTAssertNotNil(downloadTask);
  987. [downloadTask resume];
  988. [instrument deregisterInstrumentors];
  989. }
  990. /** Tests that downloadTaskWithRequest:completionHandler: returns a non-nil object. */
  991. - (void)testDownloadTaskWithRequestCompletionHandler {
  992. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  993. [instrument registerInstrumentors];
  994. NSURLSession *session = [NSURLSession sharedSession];
  995. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  996. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  997. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  998. void (^completionHandler)(NSURL *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  999. ^(NSURL *_Nullable location, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  1000. [expectation fulfill];
  1001. };
  1002. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
  1003. completionHandler:completionHandler];
  1004. XCTAssertNotNil(downloadTask);
  1005. [downloadTask resume];
  1006. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  1007. [instrument deregisterInstrumentors];
  1008. }
  1009. /** Tests that downloadTaskWithUrl:completionHandler: returns a non-nil object. */
  1010. - (void)testDownloadTaskWithURLCompletionHandler {
  1011. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  1012. [instrument registerInstrumentors];
  1013. NSURLSession *session = [NSURLSession sharedSession];
  1014. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  1015. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  1016. NSURLSessionDownloadTask *downloadTask = nil;
  1017. void (^completionHandler)(NSURL *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  1018. ^(NSURL *_Nullable location, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  1019. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  1020. [expectation fulfill];
  1021. };
  1022. downloadTask = [session downloadTaskWithURL:URL completionHandler:completionHandler];
  1023. XCTAssertNotNil(downloadTask);
  1024. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  1025. [downloadTask resume];
  1026. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  1027. [instrument deregisterInstrumentors];
  1028. }
  1029. /** Validate that it works with NSMutableURLRequest URLs across data, upload, and download. */
  1030. - (void)testMutableRequestURLs {
  1031. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  1032. [instrument registerInstrumentors];
  1033. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  1034. NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL];
  1035. NSURLSession *session = [NSURLSession
  1036. sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
  1037. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:URLRequest];
  1038. [dataTask resume];
  1039. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  1040. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  1041. GCDWebServerResponse *_Nonnull response) {
  1042. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  1043. }];
  1044. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:URLRequest];
  1045. [downloadTask resume];
  1046. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  1047. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  1048. GCDWebServerResponse *_Nonnull response) {
  1049. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  1050. }];
  1051. URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  1052. URLRequest.URL = URL;
  1053. URLRequest.HTTPMethod = @"POST";
  1054. NSData *uploadData = [[NSData alloc] init];
  1055. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:URLRequest
  1056. fromData:uploadData];
  1057. [uploadTask resume];
  1058. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  1059. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  1060. GCDWebServerResponse *_Nonnull response) {
  1061. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  1062. }];
  1063. NSBundle *bundle = [FPRTestUtils getBundle];
  1064. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  1065. uploadTask = [session uploadTaskWithRequest:URLRequest fromFile:fileURL];
  1066. [uploadTask resume];
  1067. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  1068. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  1069. GCDWebServerResponse *_Nonnull response) {
  1070. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  1071. }];
  1072. [instrument deregisterInstrumentors];
  1073. }
  1074. @end
  1075. #endif // SWIFT_PACKAGE