Skip to content

Commit ef9a60b

Browse files
committed
Improve tests around stopFetches and max fetches per host.
- Document where order is important when stopping fetchers. - Improve the existing tests to be more complete about what happens when stopping fetches that get deferred. This exposes a current fail case, so a TODO was left to enable part of it once things are fixed.
1 parent 3867c8a commit ef9a60b

File tree

2 files changed

+74
-20
lines changed

2 files changed

+74
-20
lines changed

Sources/Core/GTMSessionFetcherService.m

+2
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,8 @@ - (void)stopAllFetchers {
657657
[_runningFetchersByHost removeAllObjects];
658658
}
659659

660+
// Stop the delayed fetchers first so a delayed one doesn't get started when canceling
661+
// a running one.
660662
for (NSArray *delayedForHost in delayedFetchersByHost) {
661663
for (GTMSessionFetcher *fetcher in delayedForHost) {
662664
[self stopFetcher:fetcher];

UnitTests/GTMSessionFetcherServiceTest.m

+72-20
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@ - (void)testFetcherService {
304304
// We'll verify we fetched from the server the same data that is on disk.
305305
NSData *gettysburgAddress = [_testServer documentDataAtPath:kValidFileName];
306306

307-
// We'll create 10 fetchers. Only 2 should run simultaneously.
308-
// 1 should fail; the rest should succeeed.
307+
// We'll create several fetchers. Only 2 should run simultaneously (per host).
308+
// 1 should fail; a few will be stopped the rest should succeeed.
309309
const NSUInteger kMaxRunningFetchersPerHost = 2;
310310

311311
NSString *const kUserAgent = @"ServiceTest-UA";
@@ -322,10 +322,18 @@ - (void)testFetcherService {
322322
NSString *invalidFile = [kValidFileName stringByAppendingString:@"?status=400"];
323323
NSURL *invalidFileURL = [_testServer localURLForFile:invalidFile];
324324

325+
NSString *stopSilentFile = [kValidFileName stringByAppendingString:@"?stop=silent"];
326+
NSURL *stopSilentFileURL = [_testServer localURLForFile:stopSilentFile];
327+
328+
NSString *stopCallbackFile = [kValidFileName stringByAppendingString:@"?stop=callback"];
329+
NSURL *stopCallbackFileURL = [_testServer localURLForFile:stopCallbackFile];
330+
325331
NSURL *altValidURL = [_testServer localv6URLForFile:invalidFile];
326332

327333
XCTAssertEqualObjects(validFileURL.host, @"localhost", @"unexpected host");
328334
XCTAssertEqualObjects(invalidFileURL.host, @"localhost", @"unexpected host");
335+
XCTAssertEqualObjects(stopSilentFileURL.host, @"localhost", @"unexpected host");
336+
XCTAssertEqualObjects(stopCallbackFileURL.host, @"localhost", @"unexpected host");
329337
XCTAssertEqualObjects(altValidURL.host, @"::1", @"unexpected host");
330338

331339
// Make an array with the urls from the different hosts, including one
@@ -334,13 +342,20 @@ - (void)testFetcherService {
334342
for (int idx = 1; idx <= 4; idx++) [urlArray addObject:validFileURL];
335343
[urlArray addObject:invalidFileURL];
336344
for (int idx = 1; idx <= 5; idx++) [urlArray addObject:validFileURL];
345+
for (int idx = 1; idx <= 3; idx++) [urlArray addObject:stopSilentFileURL];
337346
for (int idx = 1; idx <= 5; idx++) [urlArray addObject:altValidURL];
347+
// TODO(thomasvl) currently fail: The current code paths remove these from
348+
// pending, but doesn't actually get the completions ever called as requested.
349+
// Will be fixed in follow up PRs.
350+
// for (int idx = 1; idx <= 3; idx++) [urlArray addObject:stopCallbackFileURL];
338351
for (int idx = 1; idx <= 5; idx++) [urlArray addObject:validFileURL];
352+
for (int idx = 1; idx <= 2; idx++) [urlArray addObject:stopSilentFileURL];
339353
NSUInteger totalNumberOfFetchers = urlArray.count;
340354

341355
__block NSMutableArray *pending = [NSMutableArray array];
342356
__block NSMutableArray *running = [NSMutableArray array];
343357
__block NSMutableArray *completed = [NSMutableArray array];
358+
NSMutableArray *stoppedNoCallback = [NSMutableArray array];
344359

345360
NSInteger priorityVal = 0;
346361

@@ -367,6 +382,10 @@ - (void)testFetcherService {
367382

368383
NSURLRequest *fetcherReq = fetcher.request;
369384
NSURL *fetcherReqURL = fetcherReq.URL;
385+
386+
// A fetcher that gets stopped should not trigger any notifications.
387+
XCTAssertFalse([fetcherReqURL.query hasPrefix:@"stop="]);
388+
370389
NSString *host = fetcherReqURL.host;
371390
NSUInteger numberRunning = FetchersPerHost(running, host);
372391
XCTAssertTrue(numberRunning > 0, @"count error");
@@ -403,19 +422,25 @@ - (void)testFetcherService {
403422
[completed addObject:fetcher];
404423
[running removeObject:fetcher];
405424

406-
NSString *host = fetcher.request.URL.host;
425+
// A fetcher that gets stopped should not trigger any notifications.
426+
NSURL *fetcherReqURL = fetcher.request.URL;
427+
XCTAssertFalse([fetcherReqURL.query hasPrefix:@"stop="]);
407428

429+
NSString *host = fetcherReqURL.host;
408430
NSUInteger numberRunning = FetchersPerHost(running, host);
409431
NSUInteger numberPending = FetchersPerHost(pending, host);
410432
NSUInteger numberCompleted = FetchersPerHost(completed, host);
433+
NSUInteger numberStopped = FetchersPerHost(stoppedNoCallback, host);
411434

412435
XCTAssertLessThanOrEqual(numberRunning, kMaxRunningFetchersPerHost,
413436
@"too many running");
414437
XCTAssertLessThanOrEqual(
415-
numberPending + numberRunning + numberCompleted, URLsPerHost(urlArray, host),
416-
@"%d issued running (pending:%u running:%u completed:%u)",
438+
numberPending + numberRunning + numberCompleted + numberStopped,
439+
URLsPerHost(urlArray, host),
440+
@"%d issued running (pending:%u running:%u completed:%u stopped: %u)",
417441
(unsigned int)totalNumberOfFetchers, (unsigned int)numberPending,
418-
(unsigned int)numberRunning, (unsigned int)numberCompleted);
442+
(unsigned int)numberRunning, (unsigned int)numberCompleted,
443+
(unsigned int)numberStopped);
419444

420445
// The stop notification may be posted on the main thread before or after the
421446
// fetcher service has been notified the fetcher has stopped.
@@ -429,32 +454,56 @@ - (void)testFetcherService {
429454
if (priorityVal > 1) priorityVal = -1;
430455
fetcher.servicePriority = priorityVal;
431456

457+
BOOL stopFetch = [fileURL.query hasPrefix:@"stop="];
458+
BOOL stopWithCallback = [fileURL.query isEqual:@"stop=callback"];
459+
if (stopWithCallback) {
460+
fetcher.stopFetchingTriggersCompletionHandler = YES;
461+
}
462+
432463
// Start this fetcher.
433464
[fetchersInFlight addObject:fetcher];
434465
[fetcher beginFetchWithCompletionHandler:^(NSData *fetchData, NSError *fetchError) {
435466
// Callback.
436467
XCTAssert([fetchersInFlight containsObject:fetcher]);
437468
[fetchersInFlight removeObjectIdenticalTo:fetcher];
438469

439-
// The query should be empty except for the URL with a status code.
470+
// The query should be empty except for the URL with a status code or the ones
471+
// marked for stopping.
440472
NSString *query = [fetcher.request.URL query];
441473
BOOL isValidRequest = (query.length == 0);
442474
if (isValidRequest) {
443475
XCTAssertEqualObjects(fetchData, gettysburgAddress, @"Bad fetch data");
444476
XCTAssertNil(fetchError, @"unexpected %@ %@", fetchError, fetchError.userInfo);
445477
} else {
446-
// This is the query with ?status=400.
447-
XCTAssertEqual(fetchError.code, (NSInteger)400, @"expected error");
478+
if ([query isEqual:@"stop=callback"]) {
479+
XCTAssertEqualObjects(fetchError.domain, kGTMSessionFetcherErrorDomain, @"expected error");
480+
XCTAssertEqual(fetchError.code, GTMSessionFetcherErrorUserCancelled, @"expected error");
481+
} else if ([query hasPrefix:@"stop="]) {
482+
XCTFail(@"Should not have gotten completion for stopped call");
483+
} else {
484+
// This is the query with ?status=400.
485+
XCTAssertEqual(fetchError.code, (NSInteger)400, @"expected error");
486+
}
448487
}
449488
[expectation fulfill];
450489
}];
490+
if (stopFetch) {
491+
[fetcher stopFetching];
492+
[pending removeObject:fetcher];
493+
if (!stopWithCallback) {
494+
[stoppedNoCallback addObject:fetcher];
495+
[fetchersInFlight removeObject:fetcher];
496+
[expectation fulfill];
497+
}
498+
}
451499
}
452500

453501
[self waitForExpectations:expectations timeout:_timeoutInterval];
454502

455503
XCTAssertEqual(pending.count, (NSUInteger)0, @"still pending: %@", pending);
456504
XCTAssertEqual(running.count, (NSUInteger)0, @"still running: %@", running);
457-
XCTAssertEqual(completed.count, (NSUInteger)totalNumberOfFetchers, @"incomplete");
505+
XCTAssertEqual(completed.count + stoppedNoCallback.count, (NSUInteger)totalNumberOfFetchers,
506+
@"incomplete");
458507
XCTAssertEqual(fetchersInFlight.count, (NSUInteger)0, @"Uncompleted: %@", fetchersInFlight);
459508

460509
XCTAssertEqual([service numberOfFetchers], (NSUInteger)0, @"service non-empty");
@@ -545,6 +594,9 @@ - (void)stopAllFetchersHelperUseStopAllAPI:(BOOL)useStopAllAPI
545594
fetcher.stopFetchingTriggersCompletionHandler = doStopCallbacks;
546595
[fetcher beginFetchWithCompletionHandler:^(NSData *fetchData, NSError *fetchError) {
547596
if (doStopCallbacks) {
597+
// Since they are getting stopped, they should all produce errors, not data.
598+
XCTAssertNil(fetchData);
599+
XCTAssertNotNil(fetchError);
548600
[fetcherCallbackExpectation fulfill];
549601
} else {
550602
// We shouldn't reach any of the callbacks.
@@ -560,25 +612,23 @@ - (void)stopAllFetchersHelperUseStopAllAPI:(BOOL)useStopAllAPI
560612
// We should see two fetchers running and one delayed for each host.
561613
NSArray *localhosts = [service.runningFetchersByHost objectForKey:@"localhost"];
562614
XCTAssertEqual(localhosts.count, (NSUInteger)2, @"hosts running");
615+
NSArray *localv6hosts = [service.runningFetchersByHost objectForKey:@"::1"];
616+
XCTAssertEqual(localv6hosts.count, (NSUInteger)2, @"hosts running");
563617

564618
localhosts = [service.delayedFetchersByHost objectForKey:@"localhost"];
565619
XCTAssertEqual(localhosts.count, (NSUInteger)1, @"hosts delayed");
620+
localv6hosts = [service.delayedFetchersByHost objectForKey:@"::1"];
621+
XCTAssertEqual(localv6hosts.count, (NSUInteger)1, @"hosts delayed");
566622

567623
XCTAssertNil(service.stoppedAllFetchersDate);
568624

569-
NSArray *delayedFetchersByHost;
570-
NSArray *runningFetchersByHost;
571-
572-
@synchronized(self) {
573-
GTMSessionMonitorSynchronized(self);
574-
575-
delayedFetchersByHost = service.delayedFetchersByHost.allValues;
576-
runningFetchersByHost = service.runningFetchersByHost.allValues;
577-
}
578-
579625
if (useStopAllAPI) {
580626
[service stopAllFetchers];
581627
} else {
628+
// Stop the delayed fetchers first so a delayed one doesn't get started when canceling
629+
// a running one.
630+
NSArray *delayedFetchersByHost = service.delayedFetchersByHost.allValues;
631+
NSArray *runningFetchersByHost = service.runningFetchersByHost.allValues;
582632
for (NSArray *delayedForHost in delayedFetchersByHost) {
583633
NSArray *delayed = [delayedForHost copy];
584634
for (GTMSessionFetcher *fetcher in delayed) {
@@ -603,6 +653,8 @@ - (void)stopAllFetchersHelperUseStopAllAPI:(BOOL)useStopAllAPI
603653

604654
if (useStopAllAPI) {
605655
XCTAssertNotNil(service.stoppedAllFetchersDate);
656+
} else {
657+
XCTAssertNil(service.stoppedAllFetchersDate);
606658
}
607659
}
608660

0 commit comments

Comments
 (0)