Skip to content

Commit bd314c8

Browse files
committed
Ensure fetcher authorization delays support stop callbacks.
1 parent 4d70340 commit bd314c8

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
@@ -1874,8 +1874,27 @@ - (void)endBackgroundTask {
18741874
- (void)authorizeRequest {
18751875
GTMSessionCheckNotSynchronized(self);
18761876

1877+
BOOL stopped = NO;
18771878
@synchronized(self) {
1878-
_delayState = kDelayStateAuthorizing;
1879+
if (_userStoppedFetching) {
1880+
stopped = YES;
1881+
} else {
1882+
// Go into the delayed state for getting the authorization.
1883+
_delayState = kDelayStateAuthorizing;
1884+
}
1885+
}
1886+
1887+
if (stopped) {
1888+
// We end up here if someone calls `stopFetching` from another thread/queue while
1889+
// the fetch was being started up, so while `stopFetching` did the needed shutdown
1890+
// we have to ensure the requested callback was triggered.
1891+
if (self.stopFetchingTriggersCompletionHandler) {
1892+
NSError *error = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain
1893+
code:GTMSessionFetcherErrorUserCancelled
1894+
userInfo:nil];
1895+
[self finishWithError:error shouldRetry:NO];
1896+
}
1897+
return;
18791898
}
18801899

18811900
id authorizer = self.authorizer;
@@ -1913,13 +1932,26 @@ - (void)authorizer:(nullable id __unused)auth
19131932
finishedWithError:(nullable NSError *)error {
19141933
GTMSessionCheckNotSynchronized(self);
19151934

1935+
@synchronized(self) {
1936+
// If `stopFetching` was called, do nothing, since the fetch was in a delay state
1937+
// any needed callback already happened.
1938+
if (_userStoppedFetching) {
1939+
return;
1940+
}
1941+
if (error == nil) {
1942+
_request = authorizedRequest;
1943+
1944+
// If `stopFetching` wasn't called, clear the `_delayState`, so a call after this
1945+
// point will trigger a callback as needed. This also ensure if this is going to
1946+
// error below a cancel callback couldn't also trigger.
1947+
_delayState = kDelayStateNotDelayed;
1948+
}
1949+
}
1950+
19161951
if (error != nil) {
19171952
// We can't fetch without authorization
19181953
[self failToBeginFetchWithError:(NSError *_Nonnull)error];
19191954
} else {
1920-
@synchronized(self) {
1921-
_request = authorizedRequest;
1922-
}
19231955
[self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:YES];
19241956
}
19251957
}
@@ -2166,7 +2198,12 @@ - (void)stopFetching {
21662198
// `stopFetchReleasingCallbacks:` will dequeue it if there is a sevice throttled
21672199
// delay, so the canceled callback needs to be directly triggered since the serivce
21682200
// won't attempt to restart it.
2169-
triggerCallback = _delayState == kDelayStateServiceDelayed && self.stopFetchingTriggersCompletionHandler;
2201+
//
2202+
// And the authorization delay assumes all stop notifications needed will be done
2203+
// from here.
2204+
triggerCallback =
2205+
(_delayState == kDelayStateServiceDelayed || _delayState == kDelayStateAuthorizing) &&
2206+
self.stopFetchingTriggersCompletionHandler;
21702207
} // @synchronized(self)
21712208

21722209
if (triggerCallback) {

UnitTests/GTMSessionFetcherFetchingTest.m

+14-16
Original file line numberDiff line numberDiff line change
@@ -1710,57 +1710,47 @@ - (void)testDelayedSyncAuthCancelFetchWithCallback_WithoutFetcherService {
17101710
}
17111711

17121712
- (void)testImmediateSyncAuthCancelFetchWithCallback {
1713-
XCTSkip(@"Has failed on CI, but not locally, needs investigation.");
17141713
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer syncAuthorizer]];
17151714
}
17161715

17171716
- (void)testImmediateSyncAuthCancelFetchWithCallback_WithoutFetcherService {
17181717
_fetcherService = nil;
1719-
XCTSkip(@"Has failed on CI, but not locally, needs investigation.");
17201718
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer syncAuthorizer]];
17211719
}
17221720

17231721
- (void)testDelayedAsyncAuthCancelFetchWithCallback {
1724-
XCTSkip(@"Currently fails, needs fixing.");
17251722
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizer]];
17261723
}
17271724

17281725
- (void)testDelayedAsyncAuthCancelFetchWithCallback_WithoutFetcherService {
17291726
_fetcherService = nil;
1730-
XCTSkip(@"Currently fails, needs fixing.");
17311727
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizer]];
17321728
}
17331729

17341730
- (void)testImmediateAsyncAuthCancelFetchWithCallback {
1735-
XCTSkip(@"Currently fails, needs fixing.");
17361731
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizer]];
17371732
}
17381733

17391734
- (void)testImmediateAsyncAuthCancelFetchWithCallback_WithoutFetcherService {
17401735
_fetcherService = nil;
1741-
XCTSkip(@"Currently fails, needs fixing.");
17421736
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizer]];
17431737
}
17441738

17451739
- (void)testDelayedAsyncDelayedAuthCancelFetchWithCallback {
1746-
XCTSkip(@"Currently fails, needs fixing.");
17471740
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizerDelayed:2]];
17481741
}
17491742

17501743
- (void)testDelayedAsyncDelayedAuthCancelFetchWithCallback_WithoutFetcherService {
17511744
_fetcherService = nil;
1752-
XCTSkip(@"Currently fails, needs fixing.");
17531745
[self internalCancelFetchWithCallback:1 authorizer:[TestAuthorizer asyncAuthorizerDelayed:2]];
17541746
}
17551747

17561748
- (void)testImmediateAsyncDelayedAuthCancelFetchWithCallback {
1757-
XCTSkip(@"Currently fails, needs fixing.");
17581749
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizerDelayed:1]];
17591750
}
17601751

17611752
- (void)testImmediateAsyncDelayedAuthCancelFetchWithCallback_WithoutFetcherService {
17621753
_fetcherService = nil;
1763-
XCTSkip(@"Currently fails, needs fixing.");
17641754
[self internalCancelFetchWithCallback:0 authorizer:[TestAuthorizer asyncAuthorizerDelayed:1]];
17651755
}
17661756

@@ -1774,7 +1764,17 @@ - (void)internalCancelFetchWithCallback:(unsigned int)sleepTime
17741764
#pragma clang diagnostic pop
17751765
if (!_isServerRunning) return;
17761766

1777-
CREATE_START_STOP_NOTIFICATION_EXPECTATIONS(1, 1);
1767+
// If the authorizer is async, then the fetch won't fully begin, and there won't ever be
1768+
// a start notification (and thus stop notification).
1769+
int expectedNotificationCount = ((TestAuthorizer*)authorizer).isAsync ? 0 : 1;
1770+
XCTestExpectation *fetcherStartedExpectation = nil;
1771+
XCTestExpectation *fetcherStoppedExpectation = nil;
1772+
if (expectedNotificationCount) {
1773+
fetcherStartedExpectation =
1774+
[[XCTNSNotificationExpectation alloc] initWithName:kGTMSessionFetcherStartedNotification];
1775+
fetcherStoppedExpectation =
1776+
[[XCTNSNotificationExpectation alloc] initWithName:kGTMSessionFetcherStoppedNotification];
1777+
}
17781778

17791779
FetcherNotificationsCounter *fnctr = [[FetcherNotificationsCounter alloc] init];
17801780

@@ -1799,19 +1799,17 @@ - (void)internalCancelFetchWithCallback:(unsigned int)sleepTime
17991799
}
18001800
[fetcher stopFetching];
18011801

1802-
WAIT_FOR_START_STOP_NOTIFICATION_EXPECTATIONS();
1803-
18041802
[self waitForExpectationsWithTimeout:_timeoutInterval handler:nil];
18051803

18061804
[self assertCallbacksReleasedForFetcher:fetcher];
18071805

18081806
// Check the notifications.
1809-
XCTAssertEqual(fnctr.fetchStarted, 1, @"%@", fnctr.fetchersStartedDescriptions);
1810-
XCTAssertEqual(fnctr.fetchStopped, 1, @"%@", fnctr.fetchersStoppedDescriptions);
1807+
XCTAssertEqual(fnctr.fetchStarted, expectedNotificationCount, @"%@", fnctr.fetchersStartedDescriptions);
1808+
XCTAssertEqual(fnctr.fetchStopped, fnctr.fetchStarted, @"%@", fnctr.fetchersStoppedDescriptions);
18111809
XCTAssertEqual(fnctr.fetchCompletionInvoked, 1);
18121810
#if GTM_BACKGROUND_TASK_FETCHING
18131811
[self waitForBackgroundTaskEndedNotifications:fnctr];
1814-
XCTAssertEqual(fnctr.backgroundTasksStarted.count, (NSUInteger)1);
1812+
XCTAssertEqual(fnctr.backgroundTasksStarted.count, (NSUInteger)expectedNotificationCount);
18151813
XCTAssertEqualObjects(fnctr.backgroundTasksStarted, fnctr.backgroundTasksEnded);
18161814
#endif
18171815
}

0 commit comments

Comments
 (0)