blob: a7078f6a90740c67bab348b6337f8d2b5635b09e [file] [log] [blame]
//
// CRSessionControllerTests.m
// Courier
//
// Created by Andrew Smith on 1/13/14.
// Copyright (c) 2014 Andrew B. Smith ( http://github.com/drewsmits ). All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
#import "CRTestCase.h"
#import "CRSessionController.h"
#import "CRAsyncTestHelpers.h"
#import <OHHTTPStubs/OHHTTPStubs.h>
#define kTestGroupName @"kBurritoCrew"
#define kTestGroup2Name @"kTacoCrew"
#define kTestTaskToken @"aToken"
#define kTestTask2Token @"bToken"
@interface CRSessionController (UnitTests)
@property (nonatomic, readonly) NSMutableDictionary *groups;
@property (nonatomic, readonly) NSMutableDictionary *tasksByToken;
@property (nonatomic, readonly) NSMutableDictionary *tasksByIdentifier;
@property (nonatomic, readonly) NSOperationQueue *serialQueue;
- (void)addTask:(NSURLSessionTask *)task
withToken:(NSString *)token
toGroup:(NSString *)group;
- (void)removeTaskWithToken:(NSString *)token;
- (void)logResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *)error;
@end
@interface CRSessionControllerTests : CRTestCase
@property (nonatomic, strong) CRSessionController *sessionController;
@end
@implementation CRSessionControllerTests
- (void)setUp
{
[super setUp];
_sessionController = [CRSessionController sessionControllerWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
[OHHTTPStubs removeAllStubs];
[[NSURLSessionConfiguration ephemeralSessionConfiguration].URLCache removeAllCachedResponses];
}
- (void)tearDown
{
[OHHTTPStubs removeAllStubs];
[super tearDown];
}
- (NSURLSessionTask *)googleTask
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
NSURLSessionTask *task = [_sessionController dataTaskForRequest:request completionHandler:nil];
return task;
}
#pragma mark - Config
- (void)testSessionConfig
{
XCTAssertNotNil(_sessionController.configuration,
@"Should have a non nil configuration");
}
#pragma mark -
- (void)testDataTaskForGroup
{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
return YES;
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
return [OHHTTPStubsResponse responseWithData:[@"dummyData" dataUsingEncoding:NSUTF8StringEncoding]
statusCode:301
headers:@{@"Location" : @"http://www.nest.com"}];
}];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
XCTestExpectation *expectation = [self expectationWithDescription:@"task finished"];
NSURLSessionDataTask *task = [_sessionController dataTaskForRequest:request
taskGroup:kTestGroupName
completionHandler:^(NSData *data,
NSURLResponse *response,
BOOL cachedResponse,
NSError *error) {
[expectation fulfill];
}];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
// check group
NSArray *tasks = [_sessionController.groups valueForKey:kTestGroupName];
XCTAssertEqualObjects([tasks firstObject],
task,
@"Should be the same task");
// Check tasks
XCTAssertEqual(_sessionController.tasksByToken.count,
1U,
@"Should have one task");
id key = [[_sessionController.tasksByToken allKeys] firstObject];
NSDictionary *object = [_sessionController.tasksByToken objectForKey:key];
XCTAssertEqualObjects(object[@"group"],
kTestGroupName,
@"Should have correc group name");
XCTAssertEqualObjects(object[@"task"],
task,
@"Should be the same task");
[task resume];
//
// Wait until finished
//
[self waitForExpectationsWithTimeout:1.0 handler:nil];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(_sessionController.groups.count,
0U,
@"Should have no task groups after completion");
XCTAssertEqual(_sessionController.tasksByToken.count,
0U,
@"Should have no tasks after completion");
XCTAssertEqual(_sessionController.tasksByIdentifier.count,
0U,
@"Should have no tasks after completion");
}
#pragma mark - Task Management
- (void)testAddTask
{
NSArray *tasks = [_sessionController.groups valueForKey:kTestGroupName];
XCTAssertNil(tasks, @"Should not have a task array for group");
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
tasks = [_sessionController.groups valueForKey:kTestGroupName];
XCTAssertNotNil(tasks, @"Should have a task array for group");
XCTAssertEqual(tasks.count, 1U, @"Should have one task for group");
XCTAssertEqualObjects([tasks firstObject], task, @"Should be the same task");
XCTAssertNotNil(_sessionController.tasksByToken, @"Should have a tasks by token dictionary");
XCTAssertEqual(_sessionController.tasksByToken.count, 1U, @"Should have one task for group");
XCTAssertNotNil(_sessionController.tasksByIdentifier, @"Should have a tasks by token dictionary");
XCTAssertEqual(_sessionController.tasksByIdentifier.count, 1U, @"Should have one task for group");
XCTAssertNotNil([_sessionController.tasksByIdentifier objectForKey:@(task.taskIdentifier)], @"Should have a task for task identifier");
}
- (void)testAddNilTask
{
NSURLSessionTask *task;
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
NSArray *tasks = [_sessionController.groups valueForKey:kTestGroupName];
XCTAssertNil(tasks, @"Should not have a task array for group");
XCTAssertEqual(_sessionController.tasksByToken.count, 0U, @"Should have one task for group");
XCTAssertEqual(_sessionController.tasksByIdentifier.count, 0U, @"Should have one task for group");
}
- (void)testAddTaskToNilGroup
{
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:nil];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(_sessionController.groups.count,
1U,
@"Should have one task group");
NSArray *tasks = [_sessionController.groups valueForKey:@"kCRSessionControllerGenericTaskGroup"];
XCTAssertNotNil(tasks,
@"Should have a generic task group");
XCTAssertEqual(_sessionController.tasksByToken.count, 1U, @"Should have one task for group");
XCTAssertEqual(_sessionController.tasksByIdentifier.count, 1U, @"Should have one task for group");
}
- (void)testAddTaskToEmptyStringGroup
{
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:@""];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(_sessionController.groups.count,
1U,
@"Should have one task group");
NSArray *tasks = [_sessionController.groups valueForKey:@"kCRSessionControllerGenericTaskGroup"];
XCTAssertNotNil(tasks,
@"Should not have a task array for group");
}
- (void)testRemoveTask
{
// Add task first
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
// Remove task
[_sessionController removeTaskWithToken:kTestTaskToken];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(_sessionController.groups.count,
0U,
@"Should not have task group for tasks when empty");
XCTAssertEqual(_sessionController.tasksByToken.count,
0U,
@"Should not have any tasks by token when empty");
XCTAssertEqual(_sessionController.tasksByIdentifier.count,
0U,
@"Should not have any tasks by identifier when empty");
}
- (void)testRemoveTaskFromNilGroup
{
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:nil];
// Remove task
[_sessionController removeTaskWithToken:kTestTaskToken];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(_sessionController.groups.count,
0U,
@"Should not have task group for tasks when empty");
}
- (void)testTaskWithIdentifier
{
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:nil];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
NSURLSessionTask *shouldBeTask = [_sessionController taskWithIdentifier:task.taskIdentifier];
XCTAssertEqualObjects(shouldBeTask, task, @"Tasks should be the same");
[_sessionController removeTaskWithToken:kTestTaskToken];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertNil([_sessionController taskWithIdentifier:task.taskIdentifier], @"Should not have a task with task identifier");
}
- (void)testHasTaskWithIdentifier
{
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:nil];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertTrue([_sessionController hasTaskWithIdentifier:task.taskIdentifier], @"Should have task with identifier");
[_sessionController removeTaskWithToken:kTestTaskToken];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertFalse([_sessionController hasTaskWithIdentifier:task.taskIdentifier], @"Should not have task with identifier");
}
- (void)testHasTaskInGroupWithState
{
NSURLSessionTask *task = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertTrue([_sessionController hasTasksInGroup:kTestGroupName
withState:NSURLSessionTaskStateRunning],
@"Should have task in group with running state");
[_sessionController removeTaskWithToken:kTestTaskToken];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertFalse([_sessionController hasTasksInGroup:kTestGroupName
withState:NSURLSessionTaskStateRunning],
@"Should not have task in group with running state");
}
- (void)testEndToEndHasTaskInGroupWithState
{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
return YES;
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
return [OHHTTPStubsResponse responseWithData:[@"dummyData" dataUsingEncoding:NSUTF8StringEncoding]
statusCode:301
headers:@{@"Location" : @"http://www.nest.com"}];
}];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
XCTestExpectation *expectation = [self expectationWithDescription:@"task finished"];
NSURLSessionDataTask *task = [_sessionController dataTaskForRequest:request
taskGroup:kTestGroupName
completionHandler:^(NSData *data,
NSURLResponse *response,
BOOL cachedResponse,
NSError *error) {
[expectation fulfill];
}];
XCTAssertTrue([_sessionController hasTasksInGroup:kTestGroupName
withState:NSURLSessionTaskStateSuspended],
@"Should have task in group with running state");
[task resume];
XCTAssertTrue([_sessionController hasTasksInGroup:kTestGroupName
withState:NSURLSessionTaskStateRunning],
@"Should have task in group with running state");
XCTAssertFalse([_sessionController hasTasksInGroup:kTestGroupName
withState:NSURLSessionTaskStateSuspended],
@"Should have task in group with running state");
//
// Wait until finished
//
[self waitForExpectationsWithTimeout:1.0 handler:nil];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertFalse([_sessionController hasTasksInGroup:kTestGroupName
withState:NSURLSessionTaskStateSuspended],
@"Should have task in group with running state");
XCTAssertFalse([_sessionController hasTasksInGroup:kTestGroupName
withState:NSURLSessionTaskStateRunning],
@"Should have task in group with running state");
}
#pragma mark - State Management
- (void)testSuspendTasksInGroup
{
// Add task first
NSURLSessionTask *task = [self googleTask];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
// Add task first
NSURLSessionTask *task2 = [NSURLSessionTask new];
[_sessionController addTask:task
withToken:kTestTask2Token
toGroup:kTestGroup2Name];
[_sessionController suspendTasksInGroup:kTestGroupName];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(task.state,
NSURLSessionTaskStateSuspended,
@"Task should be suspended");
XCTAssertEqual(task2.state,
NSURLSessionTaskStateRunning,
@"Task should be running");
}
- (void)testResumeTasksInGroup
{
NSURLSessionTask *task = [self googleTask];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(task.state,
NSURLSessionTaskStateSuspended,
@"Task should be suspended");
[_sessionController resumeTasksInGroup:kTestGroupName];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(task.state,
NSURLSessionTaskStateRunning,
@"Task should be running");
}
- (void)testCancelTasksInGroup
{
NSURLSessionTask *task = [self googleTask];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
[_sessionController cancelTasksInGroup:kTestGroupName];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(task.state,
NSURLSessionTaskStateCanceling,
@"Task should be canceled");
}
- (void)testSuspendAllTasks
{
NSURLSessionTask *task = [self googleTask];
[task resume];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
// Add task first
NSURLSessionTask *task2 = [self googleTask];
[task2 resume];
[_sessionController addTask:task2
withToken:kTestTask2Token
toGroup:kTestGroup2Name];
[_sessionController suspendAllTasks];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(task.state,
NSURLSessionTaskStateSuspended,
@"Task should be suspended");
XCTAssertEqual(task2.state,
NSURLSessionTaskStateSuspended,
@"Task should be suspended");
}
- (void)testResumeAllTasks
{
NSURLSessionTask *task = [self googleTask];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
// Add task first
NSURLSessionTask *task2 = [self googleTask];
[_sessionController addTask:task2
withToken:kTestTask2Token
toGroup:kTestGroup2Name];
[_sessionController resumeAllTasks];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
XCTAssertEqual(task.state,
NSURLSessionTaskStateRunning,
@"Task should be suspended");
XCTAssertEqual(task2.state,
NSURLSessionTaskStateRunning,
@"Task should be suspended");
}
- (void)testCancelAllTasks
{
NSURLSessionTask *task = [self googleTask];
[_sessionController addTask:task
withToken:kTestTaskToken
toGroup:kTestGroupName];
// Add task first
NSURLSessionTask *task2 = [self googleTask];
[_sessionController addTask:task2
withToken:kTestTask2Token
toGroup:kTestGroup2Name];
[_sessionController cancelAllTasks];
[_sessionController.serialQueue waitUntilAllOperationsAreFinished];
BOOL result = task.state == NSURLSessionTaskStateCanceling
|| task.state == NSURLSessionTaskStateCompleted;
XCTAssertTrue(result,
@"Task should be canceled or completed");
result = task2.state == NSURLSessionTaskStateCanceling
|| task2.state == NSURLSessionTaskStateCompleted;
XCTAssertTrue(result,
@"Task should be canceled or completed");
}
#pragma mark - Cache
- (void)testCachedResponse
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://drewsmits.com/wp-content/uploads/2013/04/logo.png"]];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
[config.URLCache removeAllCachedResponses];
config.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:1024 diskCapacity:0 diskPath:nil];
//
// Stub 200 responses
//
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
return YES;
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
return [OHHTTPStubsResponse responseWithData:[@"dummyData" dataUsingEncoding:NSUTF8StringEncoding]
statusCode:200
headers:nil];
}];
CRSessionController *sessionController = [CRSessionController sessionControllerWithConfiguration:config];
__block BOOL taskOneCached = NO;
XCTestExpectation *expectation1 = [self expectationWithDescription:@"task finished"];
NSURLSessionDataTask *task = [sessionController dataTaskForRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
BOOL cachedResponse,
NSError *error) {
taskOneCached = cachedResponse;
[expectation1 fulfill];
}];
[task resume];
[self waitForExpectationsWithTimeout:1.0 handler:nil];
__block BOOL taskTwoCached = NO;
XCTestExpectation *expectation2 = [self expectationWithDescription:@"cached task finished"];
NSURLSessionDataTask *cachedTask = [sessionController dataTaskForRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
BOOL cachedResponse,
NSError *error) {
taskTwoCached = cachedResponse;
[expectation2 fulfill];
}];
[cachedTask resume];
[self waitForExpectationsWithTimeout:1.0 handler:nil];
XCTAssertFalse(taskOneCached, @"Response should not be cached");
XCTAssertTrue(taskTwoCached, @"Response should be cached");
}
@end