/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2016 ForgeRock AS.
*/
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "FMDatabase.h"
#import "FRAError.h"
#import "FRAFMDatabaseConnectionHelper.h"
#import "FRAHotpOathMechanism.h"
#import "FRAIdentity.h"
#import "FRAIdentityDatabase.h"
#import "FRAIdentityModel.h"
#import "FRAModelsFromDatabase.h"
#import "FRANotification.h"
#import "FRAPushMechanism.h"
#import "FRATotpOathMechanism.h"
static NSString * const ReadSchema = @"read_all schema";
static NSString * const Issuer = @"issuer";
static NSString * const AccountName = @"account name";
static NSString * const ImageURL = @"image url";
static NSString * const BackgroundColour = @"background color";
static NSString * const HMACOtpType = @"hotp";
static NSString * const TimeOtpType = @"totp";
static NSString * const PushType = @"push";
static NSString * const UnknownType = @"unknown";
static NSString * const Version = @"version";
static NSString * const MechanismUID = @"mechanism uid";
static NSString * const Options = @"{}";
static NSString * const TimeReceived = @"500";
static NSString * const TimeExpired = @"time expired";
static NSString * const Data = @"{\"message_id\":\"message id\", \"push_challenge\":\"challenge_data\",\"time_to_live\":\"60.0\"}";
@interface FRAModelsFromDatabaseTest : XCTestCase
@end
@implementation FRAModelsFromDatabaseTest {
id mockSqlDatabase;
id mockIdentityDatabase;
id mockDatabase;
id mockQueryResults;
id mockIdentityModel;
}
- (void)setUp {
[super setUp];
mockSqlDatabase = OCMClassMock([FRAFMDatabaseConnectionHelper class]);
mockIdentityDatabase = OCMClassMock([FRAIdentityDatabase class]);
mockDatabase = OCMClassMock([FMDatabase class]);
mockQueryResults = OCMClassMock([FMResultSet class]);
mockIdentityModel = OCMClassMock([FRAIdentityModel class]);
}
- (void)tearDown {
[mockSqlDatabase stopMocking];
[mockIdentityDatabase stopMocking];
[mockDatabase stopMocking];
[mockIdentityModel stopMocking];
[super tearDown];
}
- (void)testGetAllIdentitiesReturnsNilIfCannotGetReadAllSchema {
OCMStub([mockSqlDatabase readSchema:@"read_all" withError:nil]).andReturn(nil);
NSArray<FRAIdentity*>* identities = [FRAModelsFromDatabase allIdentitiesWithDatabase:mockSqlDatabase identityDatabase:mockIdentityDatabase identityModel:mockIdentityModel error:nil];
XCTAssertNil(identities);
}
- (void)testGetAllIdentitiesReturnsNilIfCannotGetDatabaseConnection {
OCMStub([mockSqlDatabase readSchema:@"read_all" withError:nil]).andReturn(ReadSchema);
OCMStub([mockSqlDatabase getConnectionWithError:nil]).andReturn(nil);
NSArray<FRAIdentity*>* identities = [FRAModelsFromDatabase allIdentitiesWithDatabase:mockSqlDatabase identityDatabase:mockIdentityDatabase identityModel:mockIdentityModel error:nil];
XCTAssertNil(identities);
}
- (void)testGetAllIdentitiesReturnsNilIfCannotExecuteQueryOnDatabase {
OCMStub([mockSqlDatabase readSchema:@"read_all" withError:[OCMArg anyObjectRef]]).andReturn(ReadSchema);
OCMStub([mockSqlDatabase getConnectionWithError:[OCMArg anyObjectRef]]).andReturn(mockDatabase);
OCMStub([mockDatabase executeQuery:ReadSchema]).andReturn(nil);
NSError *error;
NSArray<FRAIdentity*>* identities = [FRAModelsFromDatabase allIdentitiesWithDatabase:mockSqlDatabase identityDatabase:mockIdentityDatabase identityModel:mockIdentityModel error:&error];
XCTAssertNil(identities);
XCTAssertNotNil(error);
}
- (void)testGetAllIdentitiesReturnsIdentityWithHMACOneTimePasswordMechanism {
OCMStub([mockSqlDatabase readSchema:@"read_all" withError:nil]).andReturn(ReadSchema);
OCMStub([mockSqlDatabase getConnectionWithError:nil]).andReturn(mockDatabase);
OCMStub([mockDatabase executeQuery:ReadSchema]).andReturn(mockQueryResults);
[self setUpDummyIdentity:HMACOtpType];
NSArray<FRAIdentity*>* identities = [FRAModelsFromDatabase allIdentitiesWithDatabase:mockSqlDatabase identityDatabase:mockIdentityDatabase identityModel:mockIdentityModel error:nil];
XCTAssertEqual(identities.count, 1);
FRAIdentity *identity = [identities objectAtIndex:0];
XCTAssertEqual(identity.issuer, Issuer);
XCTAssertEqual(identity.accountName, AccountName);
XCTAssertEqual(identity.backgroundColor, BackgroundColour);
XCTAssertEqual(identity.mechanisms.count, 1);
FRAHotpOathMechanism *mechanism = (FRAHotpOathMechanism *)[identity.mechanisms objectAtIndex:0];
XCTAssertEqual([mechanism class], [FRAHotpOathMechanism class]);
}
- (void)testGetAllIdentitiesReturnsIdentityWithTimeOneTimePasswordMechanism {
OCMStub([mockSqlDatabase readSchema:@"read_all" withError:nil]).andReturn(ReadSchema);
OCMStub([mockSqlDatabase getConnectionWithError:nil]).andReturn(mockDatabase);
OCMStub([mockDatabase executeQuery:ReadSchema]).andReturn(mockQueryResults);
[self setUpDummyIdentity:TimeOtpType];
NSArray<FRAIdentity*>* identities = [FRAModelsFromDatabase allIdentitiesWithDatabase:mockSqlDatabase identityDatabase:mockIdentityDatabase identityModel:mockIdentityModel error:nil];
XCTAssertEqual(identities.count, 1);
FRAIdentity *identity = [identities objectAtIndex:0];
XCTAssertEqual(identity.issuer, Issuer);
XCTAssertEqual(identity.accountName, AccountName);
XCTAssertEqual(identity.backgroundColor, BackgroundColour);
XCTAssertEqual(identity.mechanisms.count, 1);
FRATotpOathMechanism *mechanism = (FRATotpOathMechanism *)[identity.mechanisms objectAtIndex:0];
XCTAssertEqual([mechanism class], [FRATotpOathMechanism class]);
}
- (void)testGetAllIdentitiesReturnsIdentityWithPushMechanism {
OCMStub([mockSqlDatabase readSchema:@"read_all" withError:nil]).andReturn(ReadSchema);
OCMStub([mockSqlDatabase getConnectionWithError:nil]).andReturn(mockDatabase);
OCMStub([mockDatabase executeQuery:ReadSchema]).andReturn(mockQueryResults);
[self setUpDummyIdentity:PushType];
NSArray<FRAIdentity*>* identities = [FRAModelsFromDatabase allIdentitiesWithDatabase:mockSqlDatabase identityDatabase:mockIdentityDatabase identityModel:mockIdentityModel error:nil];
XCTAssertEqual(identities.count, 1);
FRAIdentity *identity = [identities objectAtIndex:0];
XCTAssertEqual(identity.issuer, Issuer);
XCTAssertEqual(identity.accountName, AccountName);
XCTAssertEqual(identity.backgroundColor, BackgroundColour);
XCTAssertEqual(identity.mechanisms.count, 1);
FRAPushMechanism *mechanism = (FRAPushMechanism *)[identity.mechanisms objectAtIndex:0];
FRANotification *notification = [mechanism.notifications objectAtIndex:0];
XCTAssertEqualObjects(notification.messageId, @"message id");
XCTAssertEqualObjects(notification.challenge, @"challenge_data");
XCTAssertEqualObjects(notification.timeReceived, [NSDate dateWithTimeIntervalSince1970:500]);
XCTAssertEqual(notification.timeToLive, (NSTimeInterval)60.0);
}
- (void)testGetAllIdentitiesThrowsExceptionForUnknownMechanismType {
OCMStub([mockSqlDatabase readSchema:@"read_all" withError:nil]).andReturn(ReadSchema);
OCMStub([mockSqlDatabase getConnectionWithError:nil]).andReturn(mockDatabase);
OCMStub([mockDatabase executeQuery:ReadSchema]).andReturn(mockQueryResults);
[self setUpDummyIdentity:UnknownType];
XCTAssertThrows([FRAModelsFromDatabase allIdentitiesWithDatabase:mockSqlDatabase identityDatabase:mockIdentityDatabase identityModel:mockIdentityModel error:nil]);
}
- (void)setUpDummyIdentity:(NSString *)type {
OCMExpect([mockQueryResults next]).andReturn(YES);
OCMStub([mockQueryResults stringForColumn:@"issuer"]).andReturn(Issuer);
OCMStub([mockQueryResults stringForColumn:@"accountName"]).andReturn(AccountName);
OCMStub([mockQueryResults stringForColumn:@"imageURL"]).andReturn(ImageURL);
OCMStub([mockQueryResults stringForColumn:@"bgColor"]).andReturn(BackgroundColour);
OCMStub([mockQueryResults stringForColumn:@"type"]).andReturn(type);
OCMStub([mockQueryResults stringForColumn:@"version"]).andReturn(Version);
OCMStub([mockQueryResults stringForColumn:@"mechanismUID"]).andReturn(MechanismUID);
OCMStub([mockQueryResults stringForColumn:@"options"]).andReturn(Options);
OCMStub([mockQueryResults stringForColumn:@"timeReceived"]).andReturn(TimeReceived);
OCMStub([mockQueryResults stringForColumn:@"timeExpired"]).andReturn(TimeExpired);
OCMStub([mockQueryResults stringForColumn:@"data"]).andReturn(Data);
OCMStub([mockQueryResults intForColumn:@"pending"]).andReturn(-1);
OCMStub([mockQueryResults intForColumn:@"approved"]).andReturn(0);
OCMExpect([mockQueryResults next]).andReturn(NO);
}
@end