Skip to content

Commit 4fceed3

Browse files
committed
Ensure fetcher authorization delays support stop callbacks.
1 parent 295c3f6 commit 4fceed3

File tree

2 files changed

+56
-21
lines changed

2 files changed

+56
-21
lines changed

Sources/Core/GTMSessionFetcher.m

+42-5
Original file line numberDiff line numberDiff line change
@@ -1788,8 +1788,27 @@ - (void)endBackgroundTask {
17881788
- (void)authorizeRequest {
17891789
GTMSessionCheckNotSynchronized(self);
17901790

1791+
BOOL stopped = NO;
17911792
@synchronized(self) {
1792-
_delayState = kDelayStateAuthorizing;
1793+
if (_userStoppedFetching) {
1794+
stopped = YES;
1795+
} else {
1796+
// Go into the delayed state for getting the authorization.
1797+
_delayState = kDelayStateAuthorizing;
1798+
}
1799+
}
1800+
1801+
if (stopped) {
1802+
// We end up here if someone calls `stopFetching` from another thread/queue while
1803+
// the fetch was being started up, so while `stopFetching` did the needed shutdown
1804+
// we have to ensure the requested callback was triggered.
1805+
if (self.stopFetchingTriggersCompletionHandler) {
1806+
NSError *error = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain
1807+
code:GTMSessionFetcherErrorUserCancelled
1808+
userInfo:nil];
1809+
[self finishWithError:error shouldRetry:NO];
1810+
}
1811+
return;
17931812
}
17941813

17951814
id authorizer = self.authorizer;
@@ -1827,13 +1846,26 @@ - (void)authorizer:(nullable id __unused)auth
18271846
finishedWithError:(nullable NSError *)error {
18281847
GTMSessionCheckNotSynchronized(self);
18291848

1849+
@synchronized(self) {
1850+
// If `stopFetching` was called, do nothing, since the fetch was in a delay state
1851+
// any needed callback already happened.
1852+
if (_userStoppedFetching) {
1853+
return;
1854+
}
1855+
if (error == nil) {
1856+
_request = authorizedRequest;
1857+
1858+
// If `stopFetching` wasn't called, clear the `_delayState`, so a call after this
1859+
// point will trigger a callback as needed. This also ensure if this is going to
1860+
// error below a cancel callback couldn't also trigger.
1861+
_delayState = kDelayStateNotDelayed;
1862+
}
1863+
}
1864+
18301865
if (error != nil) {
18311866
// We can't fetch without authorization
18321867
[self failToBeginFetchWithError:(NSError *_Nonnull)error];
18331868
} else {
1834-
@synchronized(self) {
1835-
_request = authorizedRequest;
1836-
}
18371869
[self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:YES];
18381870
}
18391871
}
@@ -2080,7 +2112,12 @@ - (void)stopFetching {
20802112
// `stopFetchReleasingCallbacks:` will dequeue it if there is a sevice throttled
20812113
// delay, so the canceled callback needs to be directly triggered since the serivce
20822114
// won't attempt to restart it.
2083-
triggerCallback = _delayState == kDelayStateServiceDelayed && self.stopFetchingTriggersCompletionHandler;
2115+
//
2116+
// And the authorization delay assumes all stop notifications needed will be done from
2117+
// from here.
2118+
triggerCallback =
2119+
(_delayState == kDelayStateServiceDelayed || _delayState == kDelayStateAuthorizing) &&
2120+
self.stopFetchingTriggersCompletionHandler;
20842121
} // @synchronized(self)
20852122

20862123
if (triggerCallback) {

UnitTests/GTMSessionFetcherFetchingTest.m

+14-16
Original file line numberDiff line numberDiff line change
@@ -1585,57 +1585,47 @@ - (void)testDelayedSyncAuthCancelFetchWithCallback_WithoutFetcherService {
15851585
}
15861586

15871587
- (void)testImmediateSyncAuthCancelFetchWithCallback {
1588-
XCTSkip(@"Has failed on CI, but not locally, needs investigation.");
15891588
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer syncAuthorizer]];
15901589
}
15911590

15921591
- (void)testImmediateSyncAuthCancelFetchWithCallback_WithoutFetcherService {
15931592
_fetcherService = nil;
1594-
XCTSkip(@"Has failed on CI, but not locally, needs investigation.");
15951593
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer syncAuthorizer]];
15961594
}
15971595

15981596
- (void)testDelayedAsyncAuthCancelFetchWithCallback {
1599-
XCTSkip(@"Currently fails, needs fixing.");
16001597
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizer]];
16011598
}
16021599

16031600
- (void)testDelayedAsyncAuthCancelFetchWithCallback_WithoutFetcherService {
16041601
_fetcherService = nil;
1605-
XCTSkip(@"Currently fails, needs fixing.");
16061602
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizer]];
16071603
}
16081604

16091605
- (void)testImmediateAsyncAuthCancelFetchWithCallback {
1610-
XCTSkip(@"Currently fails, needs fixing.");
16111606
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizer]];
16121607
}
16131608

16141609
- (void)testImmediateAsyncAuthCancelFetchWithCallback_WithoutFetcherService {
16151610
_fetcherService = nil;
1616-
XCTSkip(@"Currently fails, needs fixing.");
16171611
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizer]];
16181612
}
16191613

16201614
- (void)testDelayedAsyncDelayedAuthCancelFetchWithCallback {
1621-
XCTSkip(@"Currently fails, needs fixing.");
16221615
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizerDelayed:2]];
16231616
}
16241617

16251618
- (void)testDelayedAsyncDelayedAuthCancelFetchWithCallback_WithoutFetcherService {
16261619
_fetcherService = nil;
1627-
XCTSkip(@"Currently fails, needs fixing.");
16281620
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizerDelayed:2]];
16291621
}
16301622

16311623
- (void)testImmediateAsyncDelayedAuthCancelFetchWithCallback {
1632-
XCTSkip(@"Currently fails, needs fixing.");
16331624
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizerDelayed:1]];
16341625
}
16351626

16361627
- (void)testImmediateAsyncDelayedAuthCancelFetchWithCallback_WithoutFetcherService {
16371628
_fetcherService = nil;
1638-
XCTSkip(@"Currently fails, needs fixing.");
16391629
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizerDelayed:1]];
16401630
}
16411631

@@ -1649,7 +1639,17 @@ - (void)internalCancelFetchWithCallback:(unsigned int)sleepTime
16491639
#pragma clang diagnostic pop
16501640
if (!_isServerRunning) return;
16511641

1652-
CREATE_START_STOP_NOTIFICATION_EXPECTATIONS(1, 1);
1642+
// If the authorizer is async, then the fetch won't fully begin, and there won't ever be
1643+
// a start notification (and thus stop notification).
1644+
int expectedNotifications = ((TestAuthorizer*)authorizer).isAsync ? 0 : 1;
1645+
XCTestExpectation *fetcherStartedExpectation = nil;
1646+
XCTestExpectation *fetcherStoppedExpectation = nil;
1647+
if (expectedNotifications) {
1648+
fetcherStartedExpectation =
1649+
[[XCTNSNotificationExpectation alloc] initWithName:kGTMSessionFetcherStartedNotification];
1650+
fetcherStoppedExpectation =
1651+
[[XCTNSNotificationExpectation alloc] initWithName:kGTMSessionFetcherStoppedNotification];
1652+
}
16531653

16541654
FetcherNotificationsCounter *fnctr = [[FetcherNotificationsCounter alloc] init];
16551655

@@ -1674,19 +1674,17 @@ - (void)internalCancelFetchWithCallback:(unsigned int)sleepTime
16741674
}
16751675
[fetcher stopFetching];
16761676

1677-
WAIT_FOR_START_STOP_NOTIFICATION_EXPECTATIONS();
1678-
16791677
[self waitForExpectationsWithTimeout:_timeoutInterval handler:nil];
16801678

16811679
[self assertCallbacksReleasedForFetcher:fetcher];
16821680

16831681
// Check the notifications.
1684-
XCTAssertEqual(fnctr.fetchStarted, 1, @"%@", fnctr.fetchersStartedDescriptions);
1685-
XCTAssertEqual(fnctr.fetchStopped, 1, @"%@", fnctr.fetchersStoppedDescriptions);
1682+
XCTAssertEqual(fnctr.fetchStarted, expectedNotifications, @"%@", fnctr.fetchersStartedDescriptions);
1683+
XCTAssertEqual(fnctr.fetchStopped, fnctr.fetchStarted, @"%@", fnctr.fetchersStoppedDescriptions);
16861684
XCTAssertEqual(fnctr.fetchCompletionInvoked, 1);
16871685
#if GTM_BACKGROUND_TASK_FETCHING
16881686
[self waitForBackgroundTaskEndedNotifications:fnctr];
1689-
XCTAssertEqual(fnctr.backgroundTasksStarted.count, (NSUInteger)1);
1687+
XCTAssertEqual(fnctr.backgroundTasksStarted.count, (NSUInteger)expectedNotifications);
16901688
XCTAssertEqualObjects(fnctr.backgroundTasksStarted, fnctr.backgroundTasksEnded);
16911689
#endif
16921690
}

0 commit comments

Comments
 (0)