Files
firebase-ios-sdk/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm
T

309 lines
10 KiB
Plaintext
Raw Normal View History

2018-03-15 16:52:13 -07:00
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <XCTest/XCTest.h>
#include <memory>
#include <string>
// This is out of order to satisfy the linter, which doesn't realize this is
// the header corresponding to this test.
// TODO(wilhuff): move this to the top once the test filename matches
2018-03-15 16:52:13 -07:00
#include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
2018-03-22 09:51:30 -07:00
#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
2018-03-15 16:52:13 -07:00
#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
2018-03-22 09:51:30 -07:00
#include "Firestore/core/src/firebase/firestore/local/leveldb_key.h"
#include "absl/strings/string_view.h"
#include "leveldb/db.h"
2018-03-15 16:52:13 -07:00
NS_ASSUME_NONNULL_BEGIN
using firebase::firestore::local::LevelDbMutationKey;
using firebase::firestore::local::LevelDbTransaction;
using firebase::firestore::util::Path;
2018-03-15 16:52:13 -07:00
using leveldb::DB;
using leveldb::Options;
using leveldb::ReadOptions;
using leveldb::Status;
using leveldb::WriteOptions;
2018-03-15 16:52:13 -07:00
@interface FSTLevelDBTransactionTests : XCTestCase
@end
@implementation FSTLevelDBTransactionTests {
2018-06-13 08:12:09 -07:00
std::unique_ptr<DB> _db;
2018-03-15 16:52:13 -07:00
}
- (void)setUp {
Options options;
options.error_if_exists = true;
options.create_if_missing = true;
Path dir = [FSTPersistenceTestHelpers levelDBDir];
2018-03-15 16:52:13 -07:00
DB *db;
Status status = DB::Open(options, dir.ToUtf8String(), &db);
2018-03-15 16:52:13 -07:00
XCTAssert(status.ok(), @"Failed to create db: %s", status.ToString().c_str());
_db.reset(db);
}
- (void)tearDown {
_db.reset();
}
- (void)testCreateTransaction {
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testCreateTransaction");
2018-03-15 16:52:13 -07:00
std::string key = "key1";
transaction.Put(key, "value");
auto iter = transaction.NewIterator();
2018-03-15 16:52:13 -07:00
iter->Seek(key);
XCTAssertEqual(key, iter->key());
iter->Next();
XCTAssertFalse(iter->Valid());
}
- (void)testCanReadCommittedAndMutations {
const std::string committed_key1 = "c_key1";
const std::string committed_value1 = "c_value1";
const WriteOptions &writeOptions = LevelDbTransaction::DefaultWriteOptions();
// add two things committed, mutate one, add another mutation
// verify you can get the original committed, the mutation, and the addition
Status status = _db->Put(writeOptions, committed_key1, committed_value1);
XCTAssertTrue(status.ok());
const std::string committed_key2 = "c_key2";
const std::string committed_value2 = "c_value2";
status = _db->Put(writeOptions, committed_key2, committed_value2);
XCTAssertTrue(status.ok());
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testCanReadCommittedAndMutations");
2018-03-15 16:52:13 -07:00
const std::string mutation_key1 = "m_key1";
const std::string mutation_value1 = "m_value1";
transaction.Put(mutation_key1, mutation_value1);
const std::string mutation_key2 = committed_key2;
const std::string mutation_value2 = "m_value2";
transaction.Put(mutation_key2, mutation_value2);
std::string value;
status = transaction.Get(committed_key1, &value);
XCTAssertTrue(status.ok());
XCTAssertEqual(value, committed_value1);
status = transaction.Get(mutation_key1, &value);
XCTAssertTrue(status.ok());
XCTAssertEqual(value, mutation_value1);
status = transaction.Get(committed_key2, &value);
XCTAssertTrue(status.ok());
XCTAssertEqual(value, mutation_value2);
}
- (void)testDeleteCommitted {
// add something committed, delete it, verify you can't read it
for (int i = 0; i < 3; ++i) {
Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
"value_" + std::to_string(i));
XCTAssertTrue(status.ok());
}
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testDeleteCommitted");
2018-03-15 16:52:13 -07:00
transaction.Put("key_1", "new_value");
std::string value;
Status status = transaction.Get("key_1", &value);
XCTAssertTrue(status.ok());
XCTAssertEqual(value, "new_value");
transaction.Delete("key_1");
status = transaction.Get("key_1", &value);
XCTAssertTrue(status.IsNotFound());
LevelDbTransaction::Iterator iter(&transaction);
iter.Seek("");
XCTAssertEqual(iter.key(), "key_0");
iter.Next();
XCTAssertEqual(iter.key(), "key_2");
iter.Next();
XCTAssertFalse(iter.Valid());
}
- (void)testMutateDeleted {
// delete something, then mutate it, then read it.
// Also include an actual deletion
for (int i = 0; i < 4; ++i) {
Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
"value_" + std::to_string(i));
XCTAssertTrue(status.ok());
}
std::string value;
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testMutateDeleted");
2018-03-15 16:52:13 -07:00
transaction.Delete("key_1");
Status status = transaction.Get("key_1", &value);
XCTAssertTrue(status.IsNotFound());
transaction.Put("key_1", "new_value");
status = transaction.Get("key_1", &value);
XCTAssertTrue(status.ok());
XCTAssertEqual(value, "new_value");
transaction.Delete("key_3");
LevelDbTransaction::Iterator iter(&transaction);
iter.Seek("");
XCTAssertEqual(iter.key(), "key_0");
iter.Next();
XCTAssertEqual(iter.key(), "key_1");
XCTAssertEqual(iter.value(), "new_value");
iter.Next();
XCTAssertEqual(iter.key(), "key_2");
iter.Next();
XCTAssertFalse(iter.Valid());
// Commit, then check underlying db.
transaction.Commit();
const ReadOptions &readOptions = LevelDbTransaction::DefaultReadOptions();
status = _db->Get(readOptions, "key_0", &value);
XCTAssertTrue(status.ok());
XCTAssertEqual("value_0", value);
status = _db->Get(readOptions, "key_1", &value);
XCTAssertTrue(status.ok());
XCTAssertEqual("new_value", value);
status = _db->Get(readOptions, "key_2", &value);
XCTAssertTrue(status.ok());
XCTAssertEqual("value_2", value);
status = _db->Get(readOptions, "key_3", &value);
XCTAssertTrue(status.IsNotFound());
}
- (void)testProtobufSupport {
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testProtobufSupport");
2018-03-15 16:52:13 -07:00
FSTPBTarget *target = [FSTPBTarget message];
target.targetId = 1;
target.lastListenSequenceNumber = 2;
std::string key("theKey");
transaction.Put(key, target);
std::string value;
Status status = transaction.Get("theKey", &value);
NSData *result = [[NSData alloc] initWithBytesNoCopy:(void *)value.data()
length:value.size()
freeWhenDone:NO];
2018-03-15 16:52:13 -07:00
NSError *error;
FSTPBTarget *parsed = [FSTPBTarget parseFromData:result error:&error];
XCTAssertNil(error);
XCTAssertTrue([target isEqual:parsed]);
}
- (void)testCanIterateAndDelete {
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testCanIterateAndDelete");
2018-03-15 16:52:13 -07:00
for (int i = 0; i < 4; ++i) {
transaction.Put("key_" + std::to_string(i), "value_" + std::to_string(i));
}
auto it = transaction.NewIterator();
2018-03-15 16:52:13 -07:00
it->Seek("key_0");
for (int i = 0; i < 4; ++i) {
XCTAssertTrue(it->Valid());
absl::string_view key = it->key();
2018-03-15 16:52:13 -07:00
std::string expected = "key_" + std::to_string(i);
XCTAssertEqual(expected, key);
transaction.Delete(key);
it->Next();
}
}
- (void)testCanIterateFromDeletionToCommitted {
// Write keys key_0 and key_1
for (int i = 0; i < 2; ++i) {
Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
"value_" + std::to_string(i));
XCTAssertTrue(status.ok());
}
// Create a transaction, iterate, deleting key_0. Verify we still iterate key_1.
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testCanIterateFromDeletionToCommitted");
auto it = transaction.NewIterator();
2018-03-15 16:52:13 -07:00
it->Seek("key_0");
XCTAssertTrue(it->Valid());
XCTAssertEqual("key_0", it->key());
transaction.Delete("key_0");
it->Next();
XCTAssertTrue(it->Valid());
XCTAssertEqual("key_1", it->key());
it->Next();
XCTAssertFalse(it->Valid());
}
- (void)testDeletingAheadOfAnIterator {
// Write keys
for (int i = 0; i < 4; ++i) {
Status status = _db->Put(LevelDbTransaction::DefaultWriteOptions(), "key_" + std::to_string(i),
"value_" + std::to_string(i));
XCTAssertTrue(status.ok());
}
// Create a transaction, iterate to key_1, delete key_2. Verify we still iterate key_3.
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testDeletingAheadOfAnIterator");
auto it = transaction.NewIterator();
2018-03-15 16:52:13 -07:00
it->Seek("key_0");
XCTAssertTrue(it->Valid());
XCTAssertEqual("key_0", it->key());
it->Next();
XCTAssertTrue(it->Valid());
XCTAssertEqual("key_1", it->key());
transaction.Delete("key_2");
it->Next();
XCTAssertTrue(it->Valid());
XCTAssertEqual("key_3", it->key());
XCTAssertTrue(it->Valid());
it->Next();
XCTAssertFalse(it->Valid());
}
2018-03-22 09:51:30 -07:00
- (void)testToString {
std::string key = LevelDbMutationKey::Key("user1", 42);
FSTPBWriteBatch *message = [FSTPBWriteBatch message];
message.batchId = 42;
2018-03-30 10:18:25 -07:00
LevelDbTransaction transaction(_db.get(), "testToString");
2018-03-22 09:51:30 -07:00
std::string description = transaction.ToString();
2018-03-30 10:18:25 -07:00
XCTAssertEqual(description, "<LevelDbTransaction testToString: 0 changes (0 bytes):>");
2018-03-22 09:51:30 -07:00
transaction.Put(key, message);
description = transaction.ToString();
XCTAssertEqual(description, "<LevelDbTransaction testToString: 1 changes (2 bytes):\n"
" - Put [mutation: user_id=user1 batch_id=42] (2 bytes)>");
2018-03-22 09:51:30 -07:00
std::string key2 = LevelDbMutationKey::Key("user1", 43);
transaction.Delete(key2);
description = transaction.ToString();
XCTAssertEqual(description, "<LevelDbTransaction testToString: 2 changes (2 bytes):\n"
" - Delete [mutation: user_id=user1 batch_id=43]\n"
" - Put [mutation: user_id=user1 batch_id=42] (2 bytes)>");
2018-03-22 09:51:30 -07:00
}
2018-03-15 16:52:13 -07:00
@end
NS_ASSUME_NONNULL_END