TwitterNetworkLayerTests/TNLURLSessionManagerTest.m (249 lines of code) (raw):
//
// TNLURLSessionManagerTest.m
// TwitterNetworkLayer
//
// Created on 4/1/19.
// Copyright © 2020 Twitter. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "TNLPseudoURLProtocol.h"
#import "TNLRequestOperation.h"
#import "TNLRequestOperationQueue.h"
#import "TNLURLSessionManager.h"
#define kFAKE_URL @"https://www.dummy.com/fake/url.html"
@interface TNLURLSessionManagerTest : XCTestCase
@end
@implementation TNLURLSessionManagerTest
+ (void)setUp
{
[super setUp];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:kFAKE_URL]
statusCode:200
HTTPVersion:@"http/1.1"
headerFields:nil];
NSData *data = [@"success" dataUsingEncoding:NSUTF8StringEncoding];
[TNLPseudoURLProtocol registerURLResponse:response
body:data
withEndpoint:response.URL];
}
+ (void)tearDown
{
[TNLPseudoURLProtocol unregisterEndpoint:[NSURL URLWithString:kFAKE_URL]];
[super tearDown];
}
- (void)setUp
{
}
- (void)tearDown
{
[TNLGlobalConfiguration sharedInstance].URLSessionInactivityThreshold = -1;
[TNLGlobalConfiguration sharedInstance].URLSessionPruneOptions = 0;
}
- (void)testAddingAndPruningSessions
{
__block NSUInteger prevForegroundSessionCount = 0;
__block NSUInteger prevBackgroundSessionCount = 0;
__block NSUInteger currentForegroundSessionCount = 0;
__block NSUInteger currentBackgroundSessionCount = 0;
NSURL *url = [NSURL URLWithString:kFAKE_URL];
TNLMutableRequestConfiguration *config = [TNLMutableRequestConfiguration defaultConfiguration];
config.protocolOptions |= TNLRequestProtocolOptionPseudo;
TNLRequestOperation *op = nil;
XCTestExpectation *expectation = nil;
// Forcibly prune all sessions (must do in order to ensure we know what sessions are used)
[TNLGlobalConfiguration sharedInstance].URLSessionInactivityThreshold = 0.0;
[TNLGlobalConfiguration sharedInstance].URLSessionPruneOptions = TNLGlobalConfigurationURLSessionPruneOptionNow;
expectation = [self expectationWithDescription:@"Wait For New NSURLSessions after failed Prune"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertEqual(currentForegroundSessionCount, 0);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Initial sessions
expectation = [self expectationWithDescription:@"Wait For Initial List of NSURLSessions"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
prevForegroundSessionCount = foregroundSessions.count;
prevBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
// Add a session
op = [TNLRequestOperation operationWithURL:url
configuration:config
delegate:nil];
[[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
[op waitUntilFinishedWithoutBlockingRunLoop];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For New NSURLSessions"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertGreaterThan(currentForegroundSessionCount, prevForegroundSessionCount);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Add session, different config
[config configureAsLowPriority];
op = [TNLRequestOperation operationWithURL:url
configuration:config
delegate:nil];
[[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
[op waitUntilFinishedWithoutBlockingRunLoop];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For New NSURLSessions"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertGreaterThan(currentForegroundSessionCount, prevForegroundSessionCount);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Change Timeouts, don't change session count
config.idleTimeout = 10.0;
config.attemptTimeout = 20.0;
config.operationTimeout = 30.0;
op = [TNLRequestOperation operationWithURL:url
configuration:config
delegate:nil];
[[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
[op waitUntilFinishedWithoutBlockingRunLoop];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For More New NSURLSessions"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertEqual(currentForegroundSessionCount, prevForegroundSessionCount);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Forcibly prune specific session
[[TNLGlobalConfiguration sharedInstance] pruneURLSessionMatchingRequestConfiguration:config
operationQueueId:nil];
expectation = [self expectationWithDescription:@"Wait For New NSURLSessions after Prune"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertLessThan(currentForegroundSessionCount, prevForegroundSessionCount);
XCTAssertNotEqual(currentForegroundSessionCount, 0);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Forcibly prune all sessions (won't prune due to threshold)
[TNLGlobalConfiguration sharedInstance].URLSessionInactivityThreshold = -1;
[TNLGlobalConfiguration sharedInstance].URLSessionPruneOptions = TNLGlobalConfigurationURLSessionPruneOptionNow;
expectation = [self expectationWithDescription:@"Wait For New NSURLSessions after failed Prune"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertNotEqual(currentForegroundSessionCount, 0);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Forcibly prune all sessions (will prune due to zero threshold)
[TNLGlobalConfiguration sharedInstance].URLSessionInactivityThreshold = 0.0;
[TNLGlobalConfiguration sharedInstance].URLSessionPruneOptions = TNLGlobalConfigurationURLSessionPruneOptionNow;
expectation = [self expectationWithDescription:@"Wait For New NSURLSessions after full Prune"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertEqual(currentForegroundSessionCount, 0);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
#if TARGET_OS_IOS || TARGET_OS_TVOS
// Update pruning criteria
[TNLGlobalConfiguration sharedInstance].URLSessionInactivityThreshold = 0.0;
[TNLGlobalConfiguration sharedInstance].URLSessionPruneOptions = TNLGlobalConfigurationURLSessionPruneOptionOnMemoryWarning | TNLGlobalConfigurationURLSessionPruneOptionOnApplicationBackground;
// Add a session back
op = [TNLRequestOperation operationWithURL:url
configuration:config
delegate:nil];
[[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
[op waitUntilFinishedWithoutBlockingRunLoop];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For another New NSURLSessions"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertGreaterThan(currentForegroundSessionCount, prevForegroundSessionCount);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Prune on memory warnings
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveMemoryWarningNotification object:nil];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For NSURLSessions pruning on memory warning"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertEqual(currentForegroundSessionCount, 0);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Add a session back
op = [TNLRequestOperation operationWithURL:url
configuration:config
delegate:nil];
[[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
[op waitUntilFinishedWithoutBlockingRunLoop];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For another New NSURLSessions"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertGreaterThan(currentForegroundSessionCount, prevForegroundSessionCount);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
// Prune on application background
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidBecomeActiveNotification object:nil];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For NSURLSessions pruning on application background"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertEqual(currentForegroundSessionCount, 0);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
#endif
// Add a session, but it is removed immediately
[TNLGlobalConfiguration sharedInstance].URLSessionInactivityThreshold = 0.0;
[TNLGlobalConfiguration sharedInstance].URLSessionPruneOptions = TNLGlobalConfigurationURLSessionPruneOptionAfterEveryTask;
op = [TNLRequestOperation operationWithURL:url
configuration:config
delegate:nil];
[[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
[op waitUntilFinishedWithoutBlockingRunLoop];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; // brief delay
expectation = [self expectationWithDescription:@"Wait For another New NSURLSessions but it will already be gone"];
[[TNLURLSessionManager sharedInstance] getAllURLSessions:^(NSArray<NSURLSession *> *foregroundSessions, NSArray<NSURLSession *> *backgroundSessions) {
currentForegroundSessionCount = foregroundSessions.count;
currentBackgroundSessionCount = backgroundSessions.count;
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
XCTAssertEqual(currentForegroundSessionCount, 0);
XCTAssertEqual(currentBackgroundSessionCount, prevBackgroundSessionCount);
prevForegroundSessionCount = currentForegroundSessionCount;
prevBackgroundSessionCount = currentBackgroundSessionCount;
}
@end