304 lines
9.8 KiB
Objective-C
Executable File
304 lines
9.8 KiB
Objective-C
Executable File
//
|
|
// FMDatabasePoolTests.m
|
|
// fmdb
|
|
//
|
|
// Created by Graham Dennis on 24/11/2013.
|
|
//
|
|
//
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
@interface FMDatabasePoolTests : FMDBTempDBTests
|
|
|
|
@property FMDatabasePool *pool;
|
|
|
|
@end
|
|
|
|
@implementation FMDatabasePoolTests
|
|
|
|
+ (void)populateDatabase:(FMDatabase *)db
|
|
{
|
|
[db executeUpdate:@"create table easy (a text)"];
|
|
[db executeUpdate:@"create table easy2 (a text)"];
|
|
|
|
[db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];
|
|
[db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];
|
|
[db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];
|
|
|
|
[db executeUpdate:@"create table likefoo (foo text)"];
|
|
[db executeUpdate:@"insert into likefoo values ('hi')"];
|
|
[db executeUpdate:@"insert into likefoo values ('hello')"];
|
|
[db executeUpdate:@"insert into likefoo values ('not')"];
|
|
}
|
|
|
|
- (void)setUp
|
|
{
|
|
[super setUp];
|
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
|
|
|
[self setPool:[FMDatabasePool databasePoolWithPath:self.databasePath]];
|
|
|
|
[[self pool] setDelegate:self];
|
|
|
|
}
|
|
|
|
- (void)tearDown
|
|
{
|
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
|
[super tearDown];
|
|
}
|
|
|
|
- (void)testPoolIsInitiallyEmpty
|
|
{
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)0, @"Pool should be empty on creation");
|
|
}
|
|
|
|
- (void)testDatabaseCreation
|
|
{
|
|
__block FMDatabase *db1;
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1, @"Should only have one database at this point");
|
|
|
|
db1 = db;
|
|
|
|
}];
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
XCTAssertEqualObjects(db, db1, @"We should get the same database back because there was no need to create a new one");
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db2) {
|
|
XCTAssertNotEqualObjects(db2, db, @"We should get a different database because the first was in use.");
|
|
}];
|
|
|
|
}];
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)2);
|
|
|
|
[self.pool releaseAllDatabases];
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)0, @"We should be back to zero databases again");
|
|
}
|
|
|
|
- (void)testCheckedInCheckoutOutCount
|
|
{
|
|
[self.pool inDatabase:^(FMDatabase *aDb) {
|
|
|
|
XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)0);
|
|
XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)1);
|
|
|
|
XCTAssertTrue(([aDb executeUpdate:@"insert into easy (a) values (?)", @"hi"]));
|
|
|
|
// just for fun.
|
|
FMResultSet *rs = [aDb executeQuery:@"select * from easy"];
|
|
XCTAssertNotNil(rs);
|
|
XCTAssertTrue([rs next]);
|
|
while ([rs next]) { ; } // whatevers.
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
|
|
XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)0);
|
|
XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)1);
|
|
}];
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
|
|
}
|
|
|
|
- (void)testMaximumDatabaseLimit
|
|
{
|
|
[self.pool setMaximumNumberOfDatabasesToCreate:2];
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
[self.pool inDatabase:^(FMDatabase *db2) {
|
|
[self.pool inDatabase:^(FMDatabase *db3) {
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)2);
|
|
XCTAssertNil(db3, @"The third database must be nil because we have a maximum of 2 databases in the pool");
|
|
}];
|
|
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (void)testTransaction
|
|
{
|
|
[self.pool inTransaction:^(FMDatabase *adb, BOOL *rollback) {
|
|
[adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];
|
|
[adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];
|
|
[adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
|
|
XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)0);
|
|
XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)1);
|
|
}];
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
|
|
XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)1);
|
|
XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)0);
|
|
}
|
|
|
|
- (void)testSelect
|
|
{
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
FMResultSet *rs = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1001]];
|
|
XCTAssertNotNil(rs);
|
|
XCTAssertTrue ([rs next]);
|
|
XCTAssertFalse([rs next]);
|
|
}];
|
|
}
|
|
|
|
- (void)testTransactionRollback
|
|
{
|
|
[self.pool inDeferredTransaction:^(FMDatabase *adb, BOOL *rollback) {
|
|
XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1004]]));
|
|
XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1005]]));
|
|
XCTAssertTrue([[adb executeQuery:@"select * from easy where a == '1004'"] next], @"1004 should be in database");
|
|
|
|
*rollback = YES;
|
|
}];
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
XCTAssertFalse([[db executeQuery:@"select * from easy where a == '1004'"] next], @"1004 should not be in database");
|
|
}];
|
|
|
|
XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
|
|
XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)1);
|
|
XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)0);
|
|
}
|
|
|
|
- (void)testSavepoint
|
|
{
|
|
NSError *err = [self.pool inSavePoint:^(FMDatabase *db, BOOL *rollback) {
|
|
[db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1006]];
|
|
}];
|
|
|
|
XCTAssertNil(err);
|
|
}
|
|
|
|
- (void)testNestedSavepointRollback
|
|
{
|
|
NSError *err = [self.pool inSavePoint:^(FMDatabase *adb, BOOL *rollback) {
|
|
XCTAssertFalse([adb hadError]);
|
|
XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1009]]));
|
|
|
|
[adb inSavePoint:^(BOOL *arollback) {
|
|
XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1010]]));
|
|
*arollback = YES;
|
|
}];
|
|
}];
|
|
|
|
|
|
XCTAssertNil(err);
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
FMResultSet *rs = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1009]];
|
|
XCTAssertTrue ([rs next]);
|
|
XCTAssertFalse([rs next]); // close it out.
|
|
|
|
rs = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1010]];
|
|
XCTAssertFalse([rs next]);
|
|
}];
|
|
}
|
|
|
|
- (void)testLikeStringQuery
|
|
{
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
int count = 0;
|
|
FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];
|
|
while ([rsl next]) {
|
|
count++;
|
|
}
|
|
|
|
XCTAssertEqual(count, 2);
|
|
|
|
count = 0;
|
|
rsl = [db executeQuery:@"select * from likefoo where foo like ?", @"h%"];
|
|
while ([rsl next]) {
|
|
count++;
|
|
}
|
|
|
|
XCTAssertEqual(count, 2);
|
|
|
|
}];
|
|
}
|
|
|
|
- (void)testStressTest
|
|
{
|
|
size_t ops = 128;
|
|
|
|
dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
|
|
|
dispatch_apply(ops, dqueue, ^(size_t nby) {
|
|
|
|
// just mix things up a bit for demonstration purposes.
|
|
if (nby % 2 == 1) {
|
|
|
|
[NSThread sleepForTimeInterval:.001];
|
|
}
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];
|
|
XCTAssertNotNil(rsl);
|
|
int i = 0;
|
|
while ([rsl next]) {
|
|
i++;
|
|
if (nby % 3 == 1) {
|
|
[NSThread sleepForTimeInterval:.0005];
|
|
}
|
|
}
|
|
XCTAssertEqual(i, 2);
|
|
}];
|
|
});
|
|
|
|
XCTAssert([self.pool countOfOpenDatabases] < 64, @"There should be significantly less than 64 databases after that stress test");
|
|
}
|
|
|
|
|
|
- (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database {
|
|
[database setMaxBusyRetryTimeInterval:10];
|
|
// [database setCrashOnErrors:YES];
|
|
return YES;
|
|
}
|
|
|
|
- (void)testReadWriteStressTest
|
|
{
|
|
int ops = 16;
|
|
|
|
dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
|
|
|
dispatch_apply(ops, dqueue, ^(size_t nby) {
|
|
|
|
// just mix things up a bit for demonstration purposes.
|
|
if (nby % 2 == 1) {
|
|
[NSThread sleepForTimeInterval:.01];
|
|
|
|
[self.pool inTransaction:^(FMDatabase *db, BOOL *rollback) {
|
|
FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];
|
|
XCTAssertNotNil(rsl);
|
|
while ([rsl next]) {
|
|
;// whatever.
|
|
}
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
if (nby % 3 == 1) {
|
|
[NSThread sleepForTimeInterval:.01];
|
|
}
|
|
|
|
[self.pool inTransaction:^(FMDatabase *db, BOOL *rollback) {
|
|
XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('1')"]);
|
|
XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('2')"]);
|
|
XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('3')"]);
|
|
}];
|
|
});
|
|
|
|
[self.pool releaseAllDatabases];
|
|
|
|
[self.pool inDatabase:^(FMDatabase *db) {
|
|
XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('1')"]);
|
|
}];
|
|
}
|
|
|
|
@end
|