FMDatabasePoolTests.m 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //
  2. // FMDatabasePoolTests.m
  3. // fmdb
  4. //
  5. // Created by Graham Dennis on 24/11/2013.
  6. //
  7. //
  8. #import <XCTest/XCTest.h>
  9. @interface FMDatabasePoolTests : FMDBTempDBTests
  10. @property FMDatabasePool *pool;
  11. @end
  12. @implementation FMDatabasePoolTests
  13. + (void)populateDatabase:(FMDatabase *)db
  14. {
  15. [db executeUpdate:@"create table easy (a text)"];
  16. [db executeUpdate:@"create table easy2 (a text)"];
  17. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];
  18. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];
  19. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];
  20. [db executeUpdate:@"create table likefoo (foo text)"];
  21. [db executeUpdate:@"insert into likefoo values ('hi')"];
  22. [db executeUpdate:@"insert into likefoo values ('hello')"];
  23. [db executeUpdate:@"insert into likefoo values ('not')"];
  24. }
  25. - (void)setUp
  26. {
  27. [super setUp];
  28. // Put setup code here. This method is called before the invocation of each test method in the class.
  29. self.pool = [FMDatabasePool databasePoolWithPath:self.databasePath];
  30. }
  31. - (void)tearDown
  32. {
  33. // Put teardown code here. This method is called after the invocation of each test method in the class.
  34. [super tearDown];
  35. }
  36. - (void)testPoolIsInitiallyEmpty
  37. {
  38. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)0, @"Pool should be empty on creation");
  39. }
  40. - (void)testDatabaseCreation
  41. {
  42. __block FMDatabase *db1;
  43. [self.pool inDatabase:^(FMDatabase *db) {
  44. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1, @"Should only have one database at this point");
  45. db1 = db;
  46. }];
  47. [self.pool inDatabase:^(FMDatabase *db) {
  48. XCTAssertEqualObjects(db, db1, @"We should get the same database back because there was no need to create a new one");
  49. [self.pool inDatabase:^(FMDatabase *db2) {
  50. XCTAssertNotEqualObjects(db2, db, @"We should get a different database because the first was in use.");
  51. }];
  52. }];
  53. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)2);
  54. [self.pool releaseAllDatabases];
  55. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)0, @"We should be back to zero databases again");
  56. }
  57. - (void)testCheckedInCheckoutOutCount
  58. {
  59. [self.pool inDatabase:^(FMDatabase *aDb) {
  60. XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)0);
  61. XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)1);
  62. XCTAssertTrue(([aDb executeUpdate:@"insert into easy (a) values (?)", @"hi"]));
  63. // just for fun.
  64. FMResultSet *rs = [aDb executeQuery:@"select * from easy"];
  65. XCTAssertNotNil(rs);
  66. XCTAssertTrue([rs next]);
  67. while ([rs next]) { ; } // whatevers.
  68. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
  69. XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)0);
  70. XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)1);
  71. }];
  72. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
  73. }
  74. - (void)testMaximumDatabaseLimit
  75. {
  76. [self.pool setMaximumNumberOfDatabasesToCreate:2];
  77. [self.pool inDatabase:^(FMDatabase *db) {
  78. [self.pool inDatabase:^(FMDatabase *db2) {
  79. [self.pool inDatabase:^(FMDatabase *db3) {
  80. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)2);
  81. XCTAssertNil(db3, @"The third database must be nil because we have a maximum of 2 databases in the pool");
  82. }];
  83. }];
  84. }];
  85. }
  86. - (void)testTransaction
  87. {
  88. [self.pool inTransaction:^(FMDatabase *adb, BOOL *rollback) {
  89. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];
  90. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];
  91. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];
  92. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
  93. XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)0);
  94. XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)1);
  95. }];
  96. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
  97. XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)1);
  98. XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)0);
  99. }
  100. - (void)testSelect
  101. {
  102. [self.pool inDatabase:^(FMDatabase *db) {
  103. FMResultSet *rs = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1001]];
  104. XCTAssertNotNil(rs);
  105. XCTAssertTrue ([rs next]);
  106. XCTAssertFalse([rs next]);
  107. }];
  108. }
  109. - (void)testTransactionRollback
  110. {
  111. [self.pool inDeferredTransaction:^(FMDatabase *adb, BOOL *rollback) {
  112. XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1004]]));
  113. XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1005]]));
  114. XCTAssertTrue([[adb executeQuery:@"select * from easy where a == '1004'"] next], @"1004 should be in database");
  115. *rollback = YES;
  116. }];
  117. [self.pool inDatabase:^(FMDatabase *db) {
  118. XCTAssertFalse([[db executeQuery:@"select * from easy where a == '1004'"] next], @"1004 should not be in database");
  119. }];
  120. XCTAssertEqual([self.pool countOfOpenDatabases], (NSUInteger)1);
  121. XCTAssertEqual([self.pool countOfCheckedInDatabases], (NSUInteger)1);
  122. XCTAssertEqual([self.pool countOfCheckedOutDatabases], (NSUInteger)0);
  123. }
  124. - (void)testSavepoint
  125. {
  126. NSError *err = [self.pool inSavePoint:^(FMDatabase *db, BOOL *rollback) {
  127. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1006]];
  128. }];
  129. XCTAssertNil(err);
  130. }
  131. - (void)testNestedSavepointRollback
  132. {
  133. NSError *err = [self.pool inSavePoint:^(FMDatabase *adb, BOOL *rollback) {
  134. XCTAssertFalse([adb hadError]);
  135. XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1009]]));
  136. [adb inSavePoint:^(BOOL *arollback) {
  137. XCTAssertTrue(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1010]]));
  138. *arollback = YES;
  139. }];
  140. }];
  141. XCTAssertNil(err);
  142. [self.pool inDatabase:^(FMDatabase *db) {
  143. FMResultSet *rs = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1009]];
  144. XCTAssertTrue ([rs next]);
  145. XCTAssertFalse([rs next]); // close it out.
  146. rs = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1010]];
  147. XCTAssertFalse([rs next]);
  148. }];
  149. }
  150. - (void)testLikeStringQuery
  151. {
  152. [self.pool inDatabase:^(FMDatabase *db) {
  153. int count = 0;
  154. FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];
  155. while ([rsl next]) {
  156. count++;
  157. }
  158. XCTAssertEqual(count, 2);
  159. count = 0;
  160. rsl = [db executeQuery:@"select * from likefoo where foo like ?", @"h%"];
  161. while ([rsl next]) {
  162. count++;
  163. }
  164. XCTAssertEqual(count, 2);
  165. }];
  166. }
  167. - (void)testStressTest
  168. {
  169. size_t ops = 128;
  170. dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  171. dispatch_apply(ops, dqueue, ^(size_t nby) {
  172. // just mix things up a bit for demonstration purposes.
  173. if (nby % 2 == 1) {
  174. [NSThread sleepForTimeInterval:.001];
  175. }
  176. [self.pool inDatabase:^(FMDatabase *db) {
  177. FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];
  178. XCTAssertNotNil(rsl);
  179. int i = 0;
  180. while ([rsl next]) {
  181. i++;
  182. if (nby % 3 == 1) {
  183. [NSThread sleepForTimeInterval:.0005];
  184. }
  185. }
  186. XCTAssertEqual(i, 2);
  187. }];
  188. });
  189. XCTAssert([self.pool countOfOpenDatabases] < 64, @"There should be significantly less than 64 databases after that stress test");
  190. }
  191. - (void)testReadWriteStressTest
  192. {
  193. int ops = 16;
  194. dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  195. dispatch_apply(ops, dqueue, ^(size_t nby) {
  196. // just mix things up a bit for demonstration purposes.
  197. if (nby % 2 == 1) {
  198. [NSThread sleepForTimeInterval:.01];
  199. [self.pool inTransaction:^(FMDatabase *db, BOOL *rollback) {
  200. FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];
  201. XCTAssertNotNil(rsl);
  202. while ([rsl next]) {
  203. ;// whatever.
  204. }
  205. }];
  206. }
  207. if (nby % 3 == 1) {
  208. [NSThread sleepForTimeInterval:.01];
  209. }
  210. [self.pool inTransaction:^(FMDatabase *db, BOOL *rollback) {
  211. XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('1')"]);
  212. XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('2')"]);
  213. XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('3')"]);
  214. }];
  215. });
  216. [self.pool releaseAllDatabases];
  217. [self.pool inDatabase:^(FMDatabase *db) {
  218. XCTAssertTrue([db executeUpdate:@"insert into likefoo values ('1')"]);
  219. }];
  220. }
  221. @end