FPRNSURLSessionInstrumentTest.m 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  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 FPRNSURLSessionInstrumentTest : FPRTestCase
  51. /** Test server to create connections to. */
  52. @property(nonatomic) FPRHermeticTestServer *testServer;
  53. @end
  54. @implementation FPRNSURLSessionInstrumentTest
  55. - (void)setUp {
  56. [super setUp];
  57. FIRPerformance *performance = [FIRPerformance sharedInstance];
  58. [performance setDataCollectionEnabled:YES];
  59. XCTAssertFalse(self.testServer.isRunning);
  60. self.testServer = [[FPRHermeticTestServer alloc] init];
  61. [self.testServer registerTestPaths];
  62. [self.testServer start];
  63. }
  64. - (void)tearDown {
  65. [super tearDown];
  66. FIRPerformance *performance = [FIRPerformance sharedInstance];
  67. [performance setDataCollectionEnabled:NO];
  68. [self.testServer stop];
  69. [FPRConfigurations reset];
  70. }
  71. /** Waits for the server connection to finish by giving a block to run just before a response is
  72. * sent.
  73. *
  74. * @param block A block to run just after the server response is sent.
  75. */
  76. - (void)waitAndRunBlockAfterResponse:(void (^)(id self,
  77. GCDWebServerRequest *_Nonnull request,
  78. GCDWebServerResponse *_Nonnull response))block {
  79. __block BOOL loopingMainThread = YES;
  80. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  81. dispatch_semaphore_t sema = dispatch_semaphore_create(0);
  82. __weak id weakSelf = self;
  83. self.testServer.responseCompletedBlock =
  84. ^(GCDWebServerRequest *_Nonnull request, GCDWebServerResponse *_Nonnull response) {
  85. block(weakSelf, request, response);
  86. dispatch_semaphore_signal(sema);
  87. };
  88. XCTAssertEqual(
  89. dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC)), 0);
  90. loopingMainThread = NO;
  91. });
  92. // This is necessary because the FPRHermeticTestServer callbacks occur on the main thread.
  93. while (loopingMainThread) {
  94. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
  95. }
  96. }
  97. #pragma mark - Testing infrastructure and subclass instrumenting
  98. /** Tests initing of FPRNSURLSessionInstrument also inits NSURLSessionDelegate instrument. */
  99. - (void)testInit {
  100. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  101. [instrument registerInstrumentors];
  102. self.testServer.responseCompletedBlock =
  103. ^(GCDWebServerRequest *_Nonnull request, GCDWebServerResponse *_Nonnull response) {
  104. XCTAssert(instrument);
  105. XCTAssert(instrument.delegateInstrument);
  106. };
  107. [instrument deregisterInstrumentors];
  108. }
  109. /** Tests that creating a shared session returns a non-nil object. */
  110. - (void)testSharedSession {
  111. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  112. [instrument registerInstrumentors];
  113. NSURLSession *session = [NSURLSession sharedSession];
  114. XCTAssertNotNil(session);
  115. [instrument deregisterInstrumentors];
  116. }
  117. /** Tests that a method that returns an NSURLSession subclass registers that subclass. */
  118. - (void)testSubclassRegistration {
  119. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  120. [instrument registerInstrumentors];
  121. NSURLSession *session = [NSURLSession sharedSession];
  122. XCTAssertNotNil(session);
  123. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  124. [instrument deregisterInstrumentors];
  125. }
  126. /** Tests that a discovered subclass isn't registered more than once. */
  127. - (void)testSubclassIsNotRegisteredMoreThanOnce {
  128. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  129. [instrument registerInstrumentors];
  130. NSURLSession *session = [NSURLSession sharedSession];
  131. NSURLSession *session2 = [NSURLSession sharedSession];
  132. XCTAssertNotNil(session);
  133. XCTAssertNotNil(session2);
  134. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  135. [instrument deregisterInstrumentors];
  136. }
  137. /** Tests sessionWithConfiguration: with the default configurtion returns a non-nil object. */
  138. - (void)testSessionWithDefaultSessionConfiguration {
  139. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  140. [instrument registerInstrumentors];
  141. NSURLSessionConfiguration *configuration =
  142. [NSURLSessionConfiguration defaultSessionConfiguration];
  143. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  144. XCTAssertNotNil(session);
  145. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  146. [instrument deregisterInstrumentors];
  147. }
  148. /** Tests sessionWithConfiguration: with an ephemeral configuration returns a non-nil object. */
  149. - (void)testSessionWithEphemeralSessionConfiguration {
  150. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  151. [instrument registerInstrumentors];
  152. NSURLSessionConfiguration *configuration =
  153. [NSURLSessionConfiguration ephemeralSessionConfiguration];
  154. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  155. XCTAssertNotNil(session);
  156. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  157. [instrument deregisterInstrumentors];
  158. }
  159. /** Tests sessionWithConfiguration: with a background configuration returns a non-nil object. */
  160. - (void)testSessionWithBackgroundSessionConfiguration {
  161. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  162. [instrument registerInstrumentors];
  163. NSURLSessionConfiguration *configuration =
  164. [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"madeUpID"];
  165. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  166. XCTAssertNotNil(session);
  167. XCTAssertEqual(instrument.classInstrumentors.count, 2);
  168. [instrument deregisterInstrumentors];
  169. }
  170. /** Tests instrumenting an NSProxy wrapped NSURLSession object works. */
  171. - (void)testProxyWrappedSharedSession {
  172. Method method = class_getClassMethod([NSURLSession class], @selector(sharedSession));
  173. IMP originalImp = method_getImplementation(method);
  174. IMP swizzledImp = imp_implementationWithBlock(^(id session) {
  175. typedef NSURLSession *(*OriginalImp)(id, SEL);
  176. NSURLSession *originalSession = ((OriginalImp)originalImp)(session, @selector(sharedSession));
  177. return [[FPRNSURLSessionProxy alloc] initWithSession:originalSession];
  178. });
  179. method_setImplementation(method, swizzledImp);
  180. XCTAssertEqual([[NSURLSession sharedSession] class], [FPRNSURLSessionProxy class]);
  181. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  182. [instrument registerInstrumentors];
  183. NSURLSession *session;
  184. XCTAssertNoThrow(session = [NSURLSession sharedSession]);
  185. NSURL *url = self.testServer.serverURL;
  186. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler"];
  187. NSURLSessionDownloadTask *task =
  188. [session downloadTaskWithURL:url
  189. completionHandler:^(NSURL *_Nullable location, NSURLResponse *_Nullable response,
  190. NSError *_Nullable error) {
  191. [expectation fulfill];
  192. }];
  193. [task resume];
  194. XCTAssertNotNil(task);
  195. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  196. [instrument deregisterInstrumentors];
  197. method_setImplementation(method, originalImp);
  198. XCTAssertNotEqual([[NSURLSession sharedSession] class], [FPRNSURLSessionProxy class]);
  199. }
  200. /** Tests instrumenting an NSProxy wrapped NSURLSession object works. */
  201. - (void)testProxyWrappedSessionWithConfiguration {
  202. Method method = class_getClassMethod([NSURLSession class], @selector(sessionWithConfiguration:));
  203. IMP originalImp = method_getImplementation(method);
  204. IMP swizzledImp =
  205. imp_implementationWithBlock(^(id session, NSURLSessionConfiguration *configuration) {
  206. typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *);
  207. NSURLSession *originalSession = ((OriginalImp)originalImp)(
  208. session, @selector(sessionWithConfiguration:), configuration);
  209. return [[FPRNSURLSessionProxy alloc] initWithSession:originalSession];
  210. });
  211. method_setImplementation(method, swizzledImp);
  212. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
  213. XCTAssertEqual([[NSURLSession sessionWithConfiguration:config] class],
  214. [FPRNSURLSessionProxy class]);
  215. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  216. [instrument registerInstrumentors];
  217. NSURLSession *session;
  218. XCTAssertNoThrow(session = [NSURLSession sessionWithConfiguration:config]);
  219. NSURL *url = self.testServer.serverURL;
  220. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler"];
  221. NSURLSessionDownloadTask *task =
  222. [session downloadTaskWithURL:url
  223. completionHandler:^(NSURL *_Nullable location, NSURLResponse *_Nullable response,
  224. NSError *_Nullable error) {
  225. [expectation fulfill];
  226. }];
  227. XCTAssertNotNil(task);
  228. [task resume];
  229. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  230. [instrument deregisterInstrumentors];
  231. method_setImplementation(method, originalImp);
  232. XCTAssertNotEqual([[NSURLSession sharedSession] class], [FPRNSURLSessionProxy class]);
  233. }
  234. /** Tests instrumenting an NSProxy wrapped NSURLSession object works. */
  235. - (void)testProxyWrappedSessionWithConfigurationDelegateDelegateQueue {
  236. SEL selector = @selector(sessionWithConfiguration:delegate:delegateQueue:);
  237. Method method = class_getClassMethod([NSURLSession class], selector);
  238. IMP originalImp = method_getImplementation(method);
  239. IMP swizzledImp = imp_implementationWithBlock(
  240. ^(id session, NSURLSessionConfiguration *configuration, id<NSURLSessionDelegate> *delegate,
  241. NSOperationQueue *delegateQueue) {
  242. typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *,
  243. id<NSURLSessionDelegate> *, NSOperationQueue *);
  244. NSURLSession *originalSession =
  245. ((OriginalImp)originalImp)(session, selector, configuration, delegate, delegateQueue);
  246. return [[FPRNSURLSessionProxy alloc] initWithSession:originalSession];
  247. });
  248. method_setImplementation(method, swizzledImp);
  249. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
  250. XCTAssertEqual([[NSURLSession sessionWithConfiguration:config delegate:nil
  251. delegateQueue:nil] class],
  252. [FPRNSURLSessionProxy class]);
  253. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  254. [instrument registerInstrumentors];
  255. NSURLSession *session;
  256. XCTAssertNoThrow(session = [NSURLSession sessionWithConfiguration:config
  257. delegate:nil
  258. delegateQueue:nil]);
  259. NSURL *url = self.testServer.serverURL;
  260. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler"];
  261. NSURLSessionDownloadTask *task =
  262. [session downloadTaskWithURL:url
  263. completionHandler:^(NSURL *_Nullable location, NSURLResponse *_Nullable response,
  264. NSError *_Nullable error) {
  265. [expectation fulfill];
  266. }];
  267. XCTAssertNotNil(task);
  268. [task resume];
  269. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  270. [instrument deregisterInstrumentors];
  271. method_setImplementation(method, originalImp);
  272. }
  273. #pragma mark - Testing delegate method wrapping
  274. /** Tests using a nil delegate still results in tracking responses. */
  275. - (void)testSessionWithConfigurationDelegateDelegateQueueWithNilDelegate {
  276. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  277. [instrument registerInstrumentors];
  278. NSURLSessionConfiguration *configuration =
  279. [NSURLSessionConfiguration defaultSessionConfiguration];
  280. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  281. delegate:nil
  282. delegateQueue:nil];
  283. NSURLRequest *request = [NSURLRequest requestWithURL:self.testServer.serverURL];
  284. NSURLSessionTask *task;
  285. @autoreleasepool {
  286. task = [session dataTaskWithRequest:request];
  287. XCTAssertNotNil(task);
  288. [task resume];
  289. XCTAssertNotNil(session.delegate); // Not sure this is the desired behavior.
  290. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  291. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  292. GCDWebServerResponse *_Nonnull response) {
  293. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:task]);
  294. }];
  295. }
  296. [instrument deregisterInstrumentors];
  297. }
  298. /** Tests that the delegate class isn't instrumented more than once. */
  299. - (void)testDelegateClassOnlyRegisteredOnce {
  300. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  301. [instrument registerInstrumentors];
  302. FPRNSURLSessionCompleteTestDelegate *delegate =
  303. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  304. NSURLSessionConfiguration *configuration =
  305. [NSURLSessionConfiguration defaultSessionConfiguration];
  306. [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:nil];
  307. [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:nil];
  308. XCTAssertEqual(instrument.delegateInstrument.classInstrumentors.count, 1);
  309. XCTAssertEqual(instrument.delegateInstrument.instrumentedClasses.count, 1);
  310. [instrument deregisterInstrumentors];
  311. }
  312. /** Tests that the called delegate selector is wrapped and calls through. */
  313. - (void)testDelegateURLSessionTaskDidCompleteWithError {
  314. [self.testServer stop];
  315. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  316. [instrument registerInstrumentors];
  317. FPRNSURLSessionCompleteTestDelegate *delegate =
  318. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  319. // This request needs to fail.
  320. NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://nonurl"]];
  321. NSURLSessionConfiguration *configuration =
  322. [NSURLSessionConfiguration defaultSessionConfiguration];
  323. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  324. delegate:delegate
  325. delegateQueue:nil];
  326. NSURLSessionTask *task;
  327. @autoreleasepool {
  328. task = [session dataTaskWithRequest:request];
  329. [task resume];
  330. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  331. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
  332. }
  333. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:task]);
  334. XCTAssertTrue(delegate.URLSessionTaskDidCompleteWithErrorCalled);
  335. [instrument deregisterInstrumentors];
  336. [self.testServer start];
  337. }
  338. /** Tests that the called delegate selector is wrapped and calls through. */
  339. - (void)testDelegateURLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedToSend {
  340. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  341. [instrument registerInstrumentors];
  342. FPRNSURLSessionCompleteTestDelegate *delegate =
  343. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  344. NSURLSessionConfiguration *configuration =
  345. [NSURLSessionConfiguration defaultSessionConfiguration];
  346. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  347. delegate:delegate
  348. delegateQueue:nil];
  349. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  350. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  351. request.HTTPMethod = @"POST";
  352. NSBundle *bundle = [FPRTestUtils getBundle];
  353. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  354. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:fileURL];
  355. [uploadTask resume];
  356. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  357. FPRNetworkTrace *networkTrace = [FPRNetworkTrace networkTraceFromObject:uploadTask];
  358. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  359. GCDWebServerResponse *_Nonnull response) {
  360. XCTAssertTrue(delegate.URLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedCalled);
  361. XCTAssert(networkTrace.requestSize > 0);
  362. XCTAssert(
  363. [networkTrace
  364. timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
  365. andState:FPRNetworkTraceCheckpointStateRequestCompleted] > 0);
  366. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  367. }];
  368. [instrument deregisterInstrumentors];
  369. }
  370. /** Tests that the called delegate selector is wrapped and calls through. */
  371. - (void)testDelegateURLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler {
  372. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  373. [instrument registerInstrumentors];
  374. FPRNSURLSessionCompleteTestDelegate *delegate =
  375. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  376. NSURLSessionConfiguration *configuration =
  377. [NSURLSessionConfiguration defaultSessionConfiguration];
  378. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testRedirect"];
  379. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  380. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  381. delegate:delegate
  382. delegateQueue:nil];
  383. NSURLSessionTask *task = [session dataTaskWithRequest:request];
  384. [task resume];
  385. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:task]);
  386. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  387. GCDWebServerResponse *_Nonnull response) {
  388. XCTAssertTrue(
  389. delegate.URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandlerCalled);
  390. }];
  391. [instrument deregisterInstrumentors];
  392. }
  393. /** Tests that the called delegate selector is wrapped and calls through. */
  394. - (void)testDelegateURLSessionDataTaskDidReceiveData {
  395. FPRNSURLSessionInstrument *instrument;
  396. NSURLSessionDataTask *dataTask;
  397. @autoreleasepool {
  398. instrument = [[FPRNSURLSessionInstrument alloc] init];
  399. [instrument registerInstrumentors];
  400. FPRNSURLSessionCompleteTestDelegate *delegate =
  401. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  402. NSURLSessionConfiguration *configuration =
  403. [NSURLSessionConfiguration defaultSessionConfiguration];
  404. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  405. delegate:delegate
  406. delegateQueue:nil];
  407. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  408. dataTask = [session dataTaskWithURL:URL];
  409. [dataTask resume];
  410. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  411. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  412. GCDWebServerResponse *_Nonnull response) {
  413. XCTAssertTrue(delegate.URLSessionDataTaskDidReceiveDataCalled);
  414. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  415. }];
  416. }
  417. [instrument deregisterInstrumentors];
  418. }
  419. /** Tests that the called delegate selector is wrapped and calls through. */
  420. - (void)testDelegateURLSessionDownloadTaskDidFinishDownloadingToURL {
  421. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  422. [instrument registerInstrumentors];
  423. FPRNSURLSessionCompleteTestDelegate *delegate =
  424. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  425. NSURLSessionConfiguration *configuration =
  426. [NSURLSessionConfiguration defaultSessionConfiguration];
  427. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  428. delegate:delegate
  429. delegateQueue:nil];
  430. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  431. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  432. [downloadTask resume];
  433. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  434. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  435. GCDWebServerResponse *_Nonnull response) {
  436. XCTAssertTrue(delegate.URLSessionDownloadTaskDidFinishDownloadingToURLCalled);
  437. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  438. }];
  439. [instrument deregisterInstrumentors];
  440. }
  441. /** Tests that the called delegate selector is wrapped and calls through. */
  442. - (void)testDelegateURLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytes {
  443. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  444. [instrument registerInstrumentors];
  445. FPRNSURLSessionTestDownloadDelegate *delegate =
  446. [[FPRNSURLSessionTestDownloadDelegate alloc] init];
  447. NSURLSessionConfiguration *configuration =
  448. [NSURLSessionConfiguration defaultSessionConfiguration];
  449. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  450. delegate:delegate
  451. delegateQueue:nil];
  452. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  453. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  454. [downloadTask resume];
  455. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
  456. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  457. XCTAssertTrue(delegate.URLSessionDownloadTaskDidResumeAtOffsetExpectedTotalBytesCalled);
  458. [instrument deregisterInstrumentors];
  459. }
  460. /** Tests that the called delegate selector is wrapped and calls through. */
  461. - (void)testDelegateURLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesExpectedToWrite {
  462. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  463. [instrument registerInstrumentors];
  464. FPRNSURLSessionCompleteTestDelegate *delegate =
  465. [[FPRNSURLSessionCompleteTestDelegate alloc] init];
  466. NSURLSessionConfiguration *configuration =
  467. [NSURLSessionConfiguration defaultSessionConfiguration];
  468. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  469. delegate:delegate
  470. delegateQueue:nil];
  471. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testBigDownload"];
  472. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:URL];
  473. [downloadTask resume];
  474. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  475. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  476. GCDWebServerResponse *_Nonnull response) {
  477. XCTAssertTrue(delegate.URLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesCalled);
  478. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
  479. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  480. }];
  481. [instrument deregisterInstrumentors];
  482. }
  483. /** Tests that even if a delegate doesn't implement a method, we add it to the delegate class. */
  484. - (void)testDelegateUnimplementedURLSessionTaskDidCompleteWithError {
  485. FPRNSURLSessionTestDelegate *delegate = [[FPRNSURLSessionTestDelegate alloc] init];
  486. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  487. [instrument registerInstrumentors];
  488. NSURLSessionConfiguration *configuration =
  489. [NSURLSessionConfiguration defaultSessionConfiguration];
  490. XCTAssertFalse([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]);
  491. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
  492. delegate:delegate
  493. delegateQueue:nil];
  494. XCTAssertTrue([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]);
  495. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:self.testServer.serverURL];
  496. [downloadTask resume];
  497. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  498. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  499. GCDWebServerResponse *_Nonnull response) {
  500. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  501. }];
  502. [instrument deregisterInstrumentors];
  503. }
  504. #pragma mark - Testing instance method wrapping
  505. /** Tests that dataTaskWithRequest: returns a non-nil object. */
  506. - (void)testDataTaskWithRequest {
  507. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  508. [instrument registerInstrumentors];
  509. NSURLSession *session = [NSURLSession sharedSession];
  510. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  511. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  512. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
  513. XCTAssertNotNil(dataTask);
  514. [dataTask resume];
  515. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  516. [instrument deregisterInstrumentors];
  517. }
  518. /** Tests that dataTaskWithRequest:completionHandler: returns a non-nil object. */
  519. - (void)testDataTaskWithRequestAndCompletionHandler {
  520. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  521. [instrument registerInstrumentors];
  522. NSURLSession *session = [NSURLSession sharedSession];
  523. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  524. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  525. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  526. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  527. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  528. [expectation fulfill];
  529. };
  530. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
  531. completionHandler:completionHandler];
  532. XCTAssertNotNil(dataTask);
  533. [dataTask resume];
  534. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  535. [instrument deregisterInstrumentors];
  536. }
  537. /** Tests that dataTaskWithRequest:completionHandler: for a POST request returns a non-nil object
  538. * and collects request size. */
  539. - (void)testDataTaskWithPostRequestAndCompletionHandler {
  540. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  541. [instrument registerInstrumentors];
  542. NSURLSession *session = [NSURLSession sharedSession];
  543. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  544. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  545. request.HTTPMethod = @"POST";
  546. request.HTTPBody = [@"sampleData" dataUsingEncoding:NSUTF8StringEncoding];
  547. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  548. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  549. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  550. [expectation fulfill];
  551. };
  552. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
  553. completionHandler:completionHandler];
  554. XCTAssertNotNil(dataTask);
  555. [dataTask resume];
  556. FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:dataTask];
  557. XCTAssertEqual(trace.requestSize, 10);
  558. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  559. [instrument deregisterInstrumentors];
  560. }
  561. /** Tests that dataTaskWithUrl:completionHandler: returns a non-nil object. */
  562. - (void)testDataTaskWithUrlAndCompletionHandler {
  563. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  564. [instrument registerInstrumentors];
  565. NSURLSession *session = [NSURLSession sharedSession];
  566. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  567. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  568. NSURLSessionDataTask *dataTask = nil;
  569. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  570. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  571. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  572. [expectation fulfill];
  573. };
  574. dataTask = [session dataTaskWithURL:URL completionHandler:completionHandler];
  575. XCTAssertNotNil(dataTask);
  576. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  577. [dataTask resume];
  578. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  579. [instrument deregisterInstrumentors];
  580. }
  581. /** Tests that uploadTaskWithRequest:fromFile: returns a non-nil object. */
  582. - (void)testUploadTaskWithRequestFromFile {
  583. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  584. [instrument registerInstrumentors];
  585. NSURLSession *session = [NSURLSession sharedSession];
  586. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  587. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  588. NSBundle *bundle = [FPRTestUtils getBundle];
  589. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  590. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:fileURL];
  591. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  592. XCTAssertNotNil(uploadTask);
  593. [uploadTask resume];
  594. [instrument deregisterInstrumentors];
  595. }
  596. /** Tests that uploadTaskWithRequest:fromFile:completionHandler returns a non-nil object. */
  597. - (void)testUploadTaskWithRequestFromFileCompletionHandler {
  598. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  599. [instrument registerInstrumentors];
  600. NSURLSession *session = [NSURLSession sharedSession];
  601. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  602. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  603. NSBundle *bundle = [FPRTestUtils getBundle];
  604. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  605. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  606. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  607. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  608. [expectation fulfill];
  609. };
  610. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
  611. fromFile:fileURL
  612. completionHandler:completionHandler];
  613. XCTAssertNotNil(uploadTask);
  614. [uploadTask resume];
  615. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  616. [instrument deregisterInstrumentors];
  617. }
  618. /** Tests that uploadTaskWithRequest:fromData: returns a non-nil object. */
  619. - (void)testUploadTaskWithRequestFromData {
  620. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  621. [instrument registerInstrumentors];
  622. NSURLSession *session = [NSURLSession sharedSession];
  623. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  624. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  625. request.HTTPMethod = @"POST";
  626. NSData *data = [[NSData alloc] init];
  627. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data];
  628. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  629. XCTAssertNotNil(uploadTask);
  630. [uploadTask resume];
  631. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  632. GCDWebServerResponse *_Nonnull response) {
  633. XCTAssertEqual(response.statusCode, 200);
  634. [instrument deregisterInstrumentors];
  635. }];
  636. }
  637. /** Tests that uploadTaskWithRequest:fromData:completionHandler: returns a non-nil object. */
  638. - (void)testUploadTaskWithRequestFromDataCompletionHandler {
  639. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  640. [instrument registerInstrumentors];
  641. NSURLSession *session = [NSURLSession sharedSession];
  642. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  643. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  644. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  645. void (^completionHandler)(NSData *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  646. ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  647. [expectation fulfill];
  648. };
  649. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
  650. fromData:[[NSData alloc] init]
  651. completionHandler:completionHandler];
  652. XCTAssertNotNil(uploadTask);
  653. [uploadTask resume];
  654. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  655. [instrument deregisterInstrumentors];
  656. }
  657. /** Tests that uploadTaskWithStreamedRequest: returns a non-nil object. */
  658. - (void)testUploadTaskWithStreamedRequest {
  659. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  660. [instrument registerInstrumentors];
  661. NSURLSession *session = [NSURLSession sharedSession];
  662. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  663. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  664. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithStreamedRequest:request];
  665. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  666. XCTAssertNotNil(uploadTask);
  667. [uploadTask resume];
  668. [instrument deregisterInstrumentors];
  669. }
  670. /** Tests that downloadTaskWithRequest: returns a non-nil object. */
  671. - (void)testDownloadTaskWithRequest {
  672. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  673. [instrument registerInstrumentors];
  674. NSURLSession *session = [NSURLSession sharedSession];
  675. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  676. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  677. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
  678. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  679. XCTAssertNotNil(downloadTask);
  680. [downloadTask resume];
  681. [instrument deregisterInstrumentors];
  682. }
  683. /** Tests that downloadTaskWithRequest:completionHandler: returns a non-nil object. */
  684. - (void)testDownloadTaskWithRequestCompletionHandler {
  685. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  686. [instrument registerInstrumentors];
  687. NSURLSession *session = [NSURLSession sharedSession];
  688. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  689. NSURLRequest *request = [NSURLRequest requestWithURL:URL];
  690. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  691. void (^completionHandler)(NSURL *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  692. ^(NSURL *_Nullable location, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  693. [expectation fulfill];
  694. };
  695. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
  696. completionHandler:completionHandler];
  697. XCTAssertNotNil(downloadTask);
  698. [downloadTask resume];
  699. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  700. [instrument deregisterInstrumentors];
  701. }
  702. /** Tests that downloadTaskWithUrl:completionHandler: returns a non-nil object. */
  703. - (void)testDownloadTaskWithURLCompletionHandler {
  704. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  705. [instrument registerInstrumentors];
  706. NSURLSession *session = [NSURLSession sharedSession];
  707. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"test"];
  708. XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler called"];
  709. NSURLSessionDownloadTask *downloadTask = nil;
  710. void (^completionHandler)(NSURL *_Nullable, NSURLResponse *_Nullable, NSError *_Nullable) =
  711. ^(NSURL *_Nullable location, NSURLResponse *_Nullable response, NSError *_Nullable error) {
  712. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  713. [expectation fulfill];
  714. };
  715. downloadTask = [session downloadTaskWithURL:URL completionHandler:completionHandler];
  716. XCTAssertNotNil(downloadTask);
  717. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  718. [downloadTask resume];
  719. [self waitForExpectationsWithTimeout:10.0 handler:nil];
  720. [instrument deregisterInstrumentors];
  721. }
  722. /** Validate that it works with NSMutableURLRequest URLs across data, upload, and download. */
  723. - (void)testMutableRequestURLs {
  724. FPRNSURLSessionInstrument *instrument = [[FPRNSURLSessionInstrument alloc] init];
  725. [instrument registerInstrumentors];
  726. NSURL *URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testDownload"];
  727. NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL];
  728. NSURLSession *session = [NSURLSession
  729. sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
  730. NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:URLRequest];
  731. [dataTask resume];
  732. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  733. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  734. GCDWebServerResponse *_Nonnull response) {
  735. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:dataTask]);
  736. }];
  737. NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:URLRequest];
  738. [downloadTask resume];
  739. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  740. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  741. GCDWebServerResponse *_Nonnull response) {
  742. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:downloadTask]);
  743. }];
  744. URL = [self.testServer.serverURL URLByAppendingPathComponent:@"testUpload"];
  745. URLRequest.URL = URL;
  746. URLRequest.HTTPMethod = @"POST";
  747. NSData *uploadData = [[NSData alloc] init];
  748. NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:URLRequest
  749. fromData:uploadData];
  750. [uploadTask resume];
  751. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  752. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  753. GCDWebServerResponse *_Nonnull response) {
  754. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  755. }];
  756. NSBundle *bundle = [FPRTestUtils getBundle];
  757. NSURL *fileURL = [bundle URLForResource:@"smallDownloadFile" withExtension:@""];
  758. uploadTask = [session uploadTaskWithRequest:URLRequest fromFile:fileURL];
  759. [uploadTask resume];
  760. XCTAssertNotNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  761. [self waitAndRunBlockAfterResponse:^(id self, GCDWebServerRequest *_Nonnull request,
  762. GCDWebServerResponse *_Nonnull response) {
  763. XCTAssertNil([FPRNetworkTrace networkTraceFromObject:uploadTask]);
  764. }];
  765. [instrument deregisterInstrumentors];
  766. }
  767. @end
  768. #endif // SWIFT_PACKAGE