forked from facebook/rocksdb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TableMock + framework for mock classes
Summary: This diff replaces BlockBasedTable in flush_job_test with TableMock, making it depend on less things and making it closer to an unit test than integration test. It also introduces a framework to compile mock classes -- Any file named *mock.cc will not be compiled into the build. It will only get compiled into the tests. What way we can mock out most other classes, Version, VersionSet, DBImpl, etc. Test Plan: flush_job_test Reviewers: ljin, rven, yhchiang, sdong Reviewed By: sdong Subscribers: dhruba, leveldb Differential Revision: https://reviews.facebook.net/D27681
- Loading branch information
1 parent
fb3f8ff
commit abac3d6
Showing
6 changed files
with
286 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. See the AUTHORS file for names of contributors. | ||
// Copyright (c) 2013, Facebook, Inc. All rights reserved. | ||
// This source code is licensed under the BSD-style license found in the | ||
// LICENSE file in the root directory of this source tree. An additional grant | ||
// of patent rights can be found in the PATENTS file in the same directory. | ||
|
||
#include "rocksdb/table_properties.h" | ||
#include "table/mock_table.h" | ||
#include "table/get_context.h" | ||
#include "db/dbformat.h" | ||
#include "port/port.h" | ||
#include "util/coding.h" | ||
|
||
namespace rocksdb { | ||
|
||
Iterator* MockTableReader::NewIterator(const ReadOptions&, Arena* arena) { | ||
return new MockTableIterator(table_); | ||
} | ||
|
||
Status MockTableReader::Get(const ReadOptions&, const Slice& key, | ||
GetContext* get_context) { | ||
std::unique_ptr<MockTableIterator> iter(new MockTableIterator(table_)); | ||
for (iter->Seek(key); iter->Valid(); iter->Next()) { | ||
ParsedInternalKey parsed_key; | ||
if (!ParseInternalKey(iter->key(), &parsed_key)) { | ||
return Status::Corruption(Slice()); | ||
} | ||
|
||
if (!get_context->SaveValue(parsed_key, iter->value())) { | ||
break; | ||
} | ||
} | ||
return Status::OK(); | ||
} | ||
|
||
std::shared_ptr<const TableProperties> MockTableReader::GetTableProperties() | ||
const { | ||
return std::shared_ptr<const TableProperties>(new TableProperties()); | ||
} | ||
|
||
MockTableFactory::MockTableFactory() : next_id_(1) {} | ||
|
||
Status MockTableFactory::NewTableReader( | ||
const ImmutableCFOptions& ioptions, const EnvOptions& env_options, | ||
const InternalKeyComparator& internal_key, | ||
unique_ptr<RandomAccessFile>&& file, uint64_t file_size, | ||
unique_ptr<TableReader>* table_reader) const { | ||
uint32_t id = GetIDFromFile(file.get()); | ||
|
||
MutexLock lock_guard(&file_system_.mutex); | ||
|
||
auto it = file_system_.files.find(id); | ||
if (it == file_system_.files.end()) { | ||
return Status::IOError("Mock file not found"); | ||
} | ||
|
||
table_reader->reset(new MockTableReader(it->second)); | ||
|
||
return Status::OK(); | ||
} | ||
|
||
TableBuilder* MockTableFactory::NewTableBuilder( | ||
const ImmutableCFOptions& ioptions, | ||
const InternalKeyComparator& internal_key, WritableFile* file, | ||
const CompressionType compression_type, | ||
const CompressionOptions& compression_opts) const { | ||
uint32_t id = GetAndWriteNextID(file); | ||
|
||
return new MockTableBuilder(id, &file_system_); | ||
} | ||
|
||
uint32_t MockTableFactory::GetAndWriteNextID(WritableFile* file) const { | ||
uint32_t next_id = next_id_.fetch_add(1); | ||
char buf[4]; | ||
EncodeFixed32(buf, next_id); | ||
file->Append(Slice(buf, 4)); | ||
return next_id; | ||
} | ||
|
||
uint32_t MockTableFactory::GetIDFromFile(RandomAccessFile* file) const { | ||
char buf[4]; | ||
Slice result; | ||
file->Read(0, 4, &result, buf); | ||
assert(result.size() == 4); | ||
return DecodeFixed32(buf); | ||
} | ||
|
||
void MockTableFactory::AssertSingleFile( | ||
const std::map<std::string, std::string>& file_contents) { | ||
ASSERT_EQ(file_system_.files.size(), 1U); | ||
ASSERT_TRUE(file_contents == file_system_.files.begin()->second); | ||
} | ||
|
||
} // namespace rocksdb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. See the AUTHORS file for names of contributors. | ||
// Copyright (c) 2013, Facebook, Inc. All rights reserved. | ||
// This source code is licensed under the BSD-style license found in the | ||
// LICENSE file in the root directory of this source tree. An additional grant | ||
// of patent rights can be found in the PATENTS file in the same directory. | ||
#pragma once | ||
#include <algorithm> | ||
#include <set> | ||
#include <memory> | ||
#include <map> | ||
#include <string> | ||
|
||
#include "rocksdb/table.h" | ||
#include "table/table_reader.h" | ||
#include "table/table_builder.h" | ||
#include "port/port.h" | ||
#include "util/mutexlock.h" | ||
#include "util/testharness.h" | ||
#include "util/testutil.h" | ||
|
||
namespace rocksdb { | ||
|
||
// NOTE this currently only supports bitwise comparator | ||
|
||
struct MockTableFileSystem { | ||
port::Mutex mutex; | ||
std::map<uint32_t, std::map<std::string, std::string>> files; | ||
}; | ||
|
||
class MockTableReader : public TableReader { | ||
public: | ||
MockTableReader(const std::map<std::string, std::string>& table) | ||
: table_(table) {} | ||
|
||
Iterator* NewIterator(const ReadOptions&, Arena* arena) override; | ||
|
||
Status Get(const ReadOptions&, const Slice& key, | ||
GetContext* get_context) override; | ||
|
||
uint64_t ApproximateOffsetOf(const Slice& key) override { return 0; } | ||
|
||
virtual size_t ApproximateMemoryUsage() const override { return 0; } | ||
|
||
void SetupForCompaction() override {} | ||
|
||
std::shared_ptr<const TableProperties> GetTableProperties() const override; | ||
|
||
~MockTableReader() {} | ||
|
||
private: | ||
const std::map<std::string, std::string>& table_; | ||
}; | ||
|
||
class MockTableIterator : public Iterator { | ||
public: | ||
explicit MockTableIterator(const std::map<std::string, std::string>& table) | ||
: table_(table) { | ||
itr_ = table_.end(); | ||
} | ||
|
||
bool Valid() const { return itr_ == table_.end(); } | ||
|
||
void SeekToFirst() { itr_ = table_.begin(); } | ||
|
||
void SeekToLast() { | ||
itr_ = table_.end(); | ||
--itr_; | ||
} | ||
|
||
void Seek(const Slice& target) { | ||
std::string str_target(target.data(), target.size()); | ||
itr_ = table_.lower_bound(str_target); | ||
} | ||
|
||
void Next() { ++itr_; } | ||
|
||
void Prev() { | ||
if (itr_ == table_.begin()) { | ||
itr_ = table_.end(); | ||
} else { | ||
--itr_; | ||
} | ||
} | ||
|
||
Slice key() const { return Slice(itr_->first); } | ||
|
||
Slice value() const { return Slice(itr_->second); } | ||
|
||
Status status() const { return Status::OK(); } | ||
|
||
private: | ||
const std::map<std::string, std::string>& table_; | ||
std::map<std::string, std::string>::const_iterator itr_; | ||
}; | ||
|
||
class MockTableBuilder : public TableBuilder { | ||
public: | ||
MockTableBuilder(uint32_t id, MockTableFileSystem* file_system) | ||
: id_(id), file_system_(file_system) {} | ||
|
||
// REQUIRES: Either Finish() or Abandon() has been called. | ||
~MockTableBuilder() {} | ||
|
||
// Add key,value to the table being constructed. | ||
// REQUIRES: key is after any previously added key according to comparator. | ||
// REQUIRES: Finish(), Abandon() have not been called | ||
void Add(const Slice& key, const Slice& value) override { | ||
table_.insert({key.ToString(), value.ToString()}); | ||
} | ||
|
||
// Return non-ok iff some error has been detected. | ||
Status status() const override { return Status::OK(); } | ||
|
||
Status Finish() override { | ||
MutexLock lock_guard(&file_system_->mutex); | ||
file_system_->files.insert({id_, table_}); | ||
return Status::OK(); | ||
} | ||
|
||
void Abandon() override {} | ||
|
||
uint64_t NumEntries() const override { return table_.size(); } | ||
|
||
uint64_t FileSize() const override { return table_.size(); } | ||
|
||
private: | ||
uint32_t id_; | ||
MockTableFileSystem* file_system_; | ||
std::map<std::string, std::string> table_; | ||
}; | ||
|
||
class MockTableFactory : public TableFactory { | ||
public: | ||
MockTableFactory(); | ||
const char* Name() const override { return "MockTable"; } | ||
Status NewTableReader(const ImmutableCFOptions& ioptions, | ||
const EnvOptions& env_options, | ||
const InternalKeyComparator& internal_key, | ||
unique_ptr<RandomAccessFile>&& file, uint64_t file_size, | ||
unique_ptr<TableReader>* table_reader) const; | ||
|
||
TableBuilder* NewTableBuilder( | ||
const ImmutableCFOptions& ioptions, | ||
const InternalKeyComparator& internal_key, WritableFile* file, | ||
const CompressionType compression_type, | ||
const CompressionOptions& compression_opts) const; | ||
|
||
virtual Status SanitizeOptions(const DBOptions& db_opts, | ||
const ColumnFamilyOptions& cf_opts) const { | ||
return Status::OK(); | ||
} | ||
|
||
virtual std::string GetPrintableTableOptions() const override { | ||
return std::string(); | ||
} | ||
|
||
// This function will assert that only a single file exists and that the | ||
// contents are equal to file_contents | ||
void AssertSingleFile( | ||
const std::map<std::string, std::string>& file_contents); | ||
|
||
private: | ||
uint32_t GetAndWriteNextID(WritableFile* file) const; | ||
uint32_t GetIDFromFile(RandomAccessFile* file) const; | ||
|
||
mutable MockTableFileSystem file_system_; | ||
mutable std::atomic<uint32_t> next_id_; | ||
}; | ||
|
||
} // namespace rocksdb |