FSTLevelDBTransactionTests.mm 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
  17. #import <XCTest/XCTest.h>
  18. #include <absl/strings/string_view.h>
  19. #include <leveldb/db.h>
  20. #import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
  21. #import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
  22. #import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
  23. #include "Firestore/core/src/firebase/firestore/local/leveldb_key.h"
  24. NS_ASSUME_NONNULL_BEGIN
  25. using leveldb::DB;
  26. using leveldb::Options;
  27. using leveldb::ReadOptions;
  28. using leveldb::WriteOptions;
  29. using leveldb::Status;
  30. using firebase::firestore::local::LevelDbMutationKey;
  31. using firebase::firestore::local::LevelDbTransaction;
  32. @interface FSTLevelDBTransactionTests : XCTestCase
  33. @end
  34. @implementation FSTLevelDBTransactionTests {
  35. std::shared_ptr<DB> _db;
  36. }
  37. - (void)setUp {
  38. Options options;
  39. options.error_if_exists = true;
  40. options.create_if_missing = true;
  41. NSString *dir = [FSTPersistenceTestHelpers levelDBDir];
  42. DB *db;
  43. Status status = DB::Open(options, [dir UTF8String], &db);
  44. XCTAssert(status.ok(), @"Failed to create db: %s", status.ToString().c_str());
  45. _db.reset(db);
  46. }
  47. - (void)tearDown {
  48. _db.reset();
  49. }
  50. - (void)testCreateTransaction {
  51. LevelDbTransaction transaction(_db.get(), "testCreateTransaction");
  52. std::string key = "key1";
  53. transaction.Put(key, "value");
  54. auto iter = transaction.NewIterator();
  55. iter->Seek(key);
  56. XCTAssertEqual(key, iter->key());
  57. iter->Next();
  58. XCTAssertFalse(iter->Valid());
  59. }
  60. - (void)testCanReadCommittedAndMutations {
  61. const std::string committed_key1 = "c_key1";
  62. const std::string committed_value1 = "c_value1";
  63. const WriteOptions &writeOptions = LevelDbTransaction::DefaultWriteOptions();
  64. // add two things committed, mutate one, add another mutation
  65. // verify you can get the original committed, the mutation, and the addition
  66. Status status = _db->Put(writeOptions, committed_key1, committed_value1);
  67. XCTAssertTrue(status.ok());
  68. const std::string committed_key2 = "c_key2";
  69. const std::string committed_value2 = "c_value2";
  70. status = _db->Put(writeOptions, committed_key2, committed_value2);
  71. XCTAssertTrue(status.ok());
  72. LevelDbTransaction transaction(_db.get(), "testCanReadCommittedAndMutations");
  73. const std::string mutation_key1 = "m_key1";
  74. const std::string mutation_value1 = "m_value1";
  75. transaction.Put(mutation_key1, mutation_value1);
  76. const std::string mutation_key2 = committed_key2;
  77. const std::string mutation_value2 = "m_value2";
  78. transaction.Put(mutation_key2, mutation_value2);
  79. std::string value;
  80. status = transaction.Get(committed_key1, &value);
  81. XCTAssertTrue(status.ok());
  82. XCTAssertEqual(value, committed_value1);
  83. status = transaction.Get(mutation_key1, &value);
  84. XCTAssertTrue(status.ok());
  85. XCTAssertEqual(value, mutation_value1);
  86. status = transaction.Get(committed_key2, &value);
  87. XCTAssertTrue(status.ok());
  88. XCTAssertEqual(value, mutation_value2);
  89. }
  90. - (void)testDeleteCommitted {
  91. // add something committed, delete it, verify you can't read it
  92. for (int i = 0; i < 3; ++i) {
  93. Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
  94. "value_" + std::to_string(i));
  95. XCTAssertTrue(status.ok());
  96. }
  97. LevelDbTransaction transaction(_db.get(), "testDeleteCommitted");
  98. transaction.Put("key_1", "new_value");
  99. std::string value;
  100. Status status = transaction.Get("key_1", &value);
  101. XCTAssertTrue(status.ok());
  102. XCTAssertEqual(value, "new_value");
  103. transaction.Delete("key_1");
  104. status = transaction.Get("key_1", &value);
  105. XCTAssertTrue(status.IsNotFound());
  106. LevelDbTransaction::Iterator iter(&transaction);
  107. iter.Seek("");
  108. XCTAssertEqual(iter.key(), "key_0");
  109. iter.Next();
  110. XCTAssertEqual(iter.key(), "key_2");
  111. iter.Next();
  112. XCTAssertFalse(iter.Valid());
  113. }
  114. - (void)testMutateDeleted {
  115. // delete something, then mutate it, then read it.
  116. // Also include an actual deletion
  117. for (int i = 0; i < 4; ++i) {
  118. Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
  119. "value_" + std::to_string(i));
  120. XCTAssertTrue(status.ok());
  121. }
  122. std::string value;
  123. LevelDbTransaction transaction(_db.get(), "testMutateDeleted");
  124. transaction.Delete("key_1");
  125. Status status = transaction.Get("key_1", &value);
  126. XCTAssertTrue(status.IsNotFound());
  127. transaction.Put("key_1", "new_value");
  128. status = transaction.Get("key_1", &value);
  129. XCTAssertTrue(status.ok());
  130. XCTAssertEqual(value, "new_value");
  131. transaction.Delete("key_3");
  132. LevelDbTransaction::Iterator iter(&transaction);
  133. iter.Seek("");
  134. XCTAssertEqual(iter.key(), "key_0");
  135. iter.Next();
  136. XCTAssertEqual(iter.key(), "key_1");
  137. XCTAssertEqual(iter.value(), "new_value");
  138. iter.Next();
  139. XCTAssertEqual(iter.key(), "key_2");
  140. iter.Next();
  141. XCTAssertFalse(iter.Valid());
  142. // Commit, then check underlying db.
  143. transaction.Commit();
  144. const ReadOptions &readOptions = LevelDbTransaction::DefaultReadOptions();
  145. status = _db->Get(readOptions, "key_0", &value);
  146. XCTAssertTrue(status.ok());
  147. XCTAssertEqual("value_0", value);
  148. status = _db->Get(readOptions, "key_1", &value);
  149. XCTAssertTrue(status.ok());
  150. XCTAssertEqual("new_value", value);
  151. status = _db->Get(readOptions, "key_2", &value);
  152. XCTAssertTrue(status.ok());
  153. XCTAssertEqual("value_2", value);
  154. status = _db->Get(readOptions, "key_3", &value);
  155. XCTAssertTrue(status.IsNotFound());
  156. }
  157. - (void)testProtobufSupport {
  158. LevelDbTransaction transaction(_db.get(), "testProtobufSupport");
  159. FSTPBTarget *target = [FSTPBTarget message];
  160. target.targetId = 1;
  161. target.lastListenSequenceNumber = 2;
  162. std::string key("theKey");
  163. transaction.Put(key, target);
  164. std::string value;
  165. Status status = transaction.Get("theKey", &value);
  166. NSData *result =
  167. [[NSData alloc] initWithBytesNoCopy:(void *)value.data() length:value.size() freeWhenDone:NO];
  168. NSError *error;
  169. FSTPBTarget *parsed = [FSTPBTarget parseFromData:result error:&error];
  170. XCTAssertNil(error);
  171. XCTAssertTrue([target isEqual:parsed]);
  172. }
  173. - (void)testCanIterateAndDelete {
  174. LevelDbTransaction transaction(_db.get(), "testCanIterateAndDelete");
  175. for (int i = 0; i < 4; ++i) {
  176. transaction.Put("key_" + std::to_string(i), "value_" + std::to_string(i));
  177. }
  178. auto it = transaction.NewIterator();
  179. it->Seek("key_0");
  180. for (int i = 0; i < 4; ++i) {
  181. XCTAssertTrue(it->Valid());
  182. const absl::string_view &key = it->key();
  183. std::string expected = "key_" + std::to_string(i);
  184. XCTAssertEqual(expected, key);
  185. transaction.Delete(key);
  186. it->Next();
  187. }
  188. }
  189. - (void)testCanIterateFromDeletionToCommitted {
  190. // Write keys key_0 and key_1
  191. for (int i = 0; i < 2; ++i) {
  192. Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
  193. "value_" + std::to_string(i));
  194. XCTAssertTrue(status.ok());
  195. }
  196. // Create a transaction, iterate, deleting key_0. Verify we still iterate key_1.
  197. LevelDbTransaction transaction(_db.get(), "testCanIterateFromDeletionToCommitted");
  198. auto it = transaction.NewIterator();
  199. it->Seek("key_0");
  200. XCTAssertTrue(it->Valid());
  201. XCTAssertEqual("key_0", it->key());
  202. transaction.Delete("key_0");
  203. it->Next();
  204. XCTAssertTrue(it->Valid());
  205. XCTAssertEqual("key_1", it->key());
  206. it->Next();
  207. XCTAssertFalse(it->Valid());
  208. }
  209. - (void)testDeletingAheadOfAnIterator {
  210. // Write keys
  211. for (int i = 0; i < 4; ++i) {
  212. Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
  213. "value_" + std::to_string(i));
  214. XCTAssertTrue(status.ok());
  215. }
  216. // Create a transaction, iterate to key_1, delete key_2. Verify we still iterate key_3.
  217. LevelDbTransaction transaction(_db.get(), "testDeletingAheadOfAnIterator");
  218. auto it = transaction.NewIterator();
  219. it->Seek("key_0");
  220. XCTAssertTrue(it->Valid());
  221. XCTAssertEqual("key_0", it->key());
  222. it->Next();
  223. XCTAssertTrue(it->Valid());
  224. XCTAssertEqual("key_1", it->key());
  225. transaction.Delete("key_2");
  226. it->Next();
  227. XCTAssertTrue(it->Valid());
  228. XCTAssertEqual("key_3", it->key());
  229. XCTAssertTrue(it->Valid());
  230. it->Next();
  231. XCTAssertFalse(it->Valid());
  232. }
  233. - (void)testToString {
  234. std::string key = LevelDbMutationKey::Key("user1", 42);
  235. FSTPBWriteBatch *message = [FSTPBWriteBatch message];
  236. message.batchId = 42;
  237. LevelDbTransaction transaction(_db.get(), "testToString");
  238. std::string description = transaction.ToString();
  239. XCTAssertEqual(description, "<LevelDbTransaction testToString: 0 changes (0 bytes):>");
  240. transaction.Put(key, message);
  241. description = transaction.ToString();
  242. XCTAssertEqual(description,
  243. "<LevelDbTransaction testToString: 1 changes (2 bytes):\n"
  244. " - Put [mutation: user_id=user1 batch_id=42] (2 bytes)>");
  245. std::string key2 = LevelDbMutationKey::Key("user1", 43);
  246. transaction.Delete(key2);
  247. description = transaction.ToString();
  248. XCTAssertEqual(description,
  249. "<LevelDbTransaction testToString: 2 changes (2 bytes):\n"
  250. " - Delete [mutation: user_id=user1 batch_id=43]\n"
  251. " - Put [mutation: user_id=user1 batch_id=42] (2 bytes)>");
  252. }
  253. @end
  254. NS_ASSUME_NONNULL_END