|
|
@ -0,0 +1,182 @@ |
|
|
|
#include "gtest/gtest.h"
|
|
|
|
// #include "leveldb/env.h"
|
|
|
|
// #include "leveldb/db.h"
|
|
|
|
#include "fielddb/field_db.h"
|
|
|
|
#include <random>
|
|
|
|
using namespace fielddb; |
|
|
|
|
|
|
|
constexpr int value_size = 2048; |
|
|
|
constexpr int data_size = 128 << 20; |
|
|
|
#define AGE_RANGE 100
|
|
|
|
std::vector<std::string> cities = { |
|
|
|
"Beijing", "Shanghai", "Guangzhou", "Shenzhen", "Hangzhou", |
|
|
|
"Chengdu", "Chongqing", "Wuhan", "Suzhou", "Tianjin" |
|
|
|
}; |
|
|
|
//检查insert和queryByIndex的数据是否对应
|
|
|
|
std::set<std::string> shanghaiKeys; |
|
|
|
std::set<std::string> age20Keys; |
|
|
|
//复杂的测试要注意这两个全局变量,目前只有InsertFieldData和InsertOneField会往里加,并且没有清理
|
|
|
|
|
|
|
|
Status OpenDB(std::string dbName, FieldDB **db) { |
|
|
|
Options options; |
|
|
|
options.create_if_missing = true; |
|
|
|
return FieldDB::OpenFieldDB(options, dbName, db); |
|
|
|
} |
|
|
|
|
|
|
|
// void ClearDB(FieldDB *db){
|
|
|
|
// //destroy和恢复没做前先用这个清理数据库,否则跑不同的数据多做几次测试会污染
|
|
|
|
// WriteOptions writeOptions;
|
|
|
|
// int key_num = data_size / value_size;
|
|
|
|
// for (int i = 0; i < key_num; i++) {
|
|
|
|
// int key_ = i+1;
|
|
|
|
// std::string key = std::to_string(key_);
|
|
|
|
// Status s = db->Delete(WriteOptions(), key);
|
|
|
|
// ASSERT_TRUE(s.ok());
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
//只插一条特定数据的测试
|
|
|
|
void InsertOneField(FieldDB *db, std::string key = "0") { |
|
|
|
WriteOptions writeOptions; |
|
|
|
FieldArray fields = { |
|
|
|
{"name", "special#" + key}, |
|
|
|
{"address", "Shanghai"}, |
|
|
|
{"age", "20"} |
|
|
|
}; |
|
|
|
Status s = db->PutFields(WriteOptions(), key, fields); |
|
|
|
ASSERT_TRUE(s.ok()); |
|
|
|
shanghaiKeys.insert(key); |
|
|
|
age20Keys.insert(key); |
|
|
|
} |
|
|
|
|
|
|
|
//与上面对应
|
|
|
|
void GetOneField(FieldDB *db, std::string key = "0") { |
|
|
|
ReadOptions readOptions; |
|
|
|
FieldArray fields_ret; |
|
|
|
Status s = db->GetFields(readOptions, key, &fields_ret); |
|
|
|
ASSERT_TRUE(s.ok()); |
|
|
|
for (const Field& pairs : fields_ret) { |
|
|
|
if (pairs.first == "name"){ |
|
|
|
ASSERT_EQ(pairs.second, "special#" + key); |
|
|
|
} else if (pairs.first == "address"){ |
|
|
|
ASSERT_EQ(pairs.second, "Shanghai"); |
|
|
|
} else if (pairs.first == "age"){ |
|
|
|
ASSERT_EQ(pairs.second, "20"); |
|
|
|
} else assert(false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void InsertFieldData(FieldDB *db, int seed = 0/*随机种子*/) { |
|
|
|
std::cout << "-------inserting-------" << std::endl; |
|
|
|
WriteOptions writeOptions; |
|
|
|
int key_num = data_size / value_size; |
|
|
|
// srand线程不安全,这种可以保证多线程时随机序列也一致
|
|
|
|
std::mt19937 rng(seed); |
|
|
|
|
|
|
|
for (int i = 0; i < key_num; i++) { |
|
|
|
int randThisTime = rng(); //确保读写一个循环只rand一次,否则随机序列会不一致
|
|
|
|
//让批量写入的key>0, 单独写入的key<=0,方便测试观察
|
|
|
|
int key_ = std::abs(randThisTime) % key_num + 1; |
|
|
|
std::string key = std::to_string(key_); |
|
|
|
|
|
|
|
std::string name = "customer#" + std::to_string(key_); |
|
|
|
std::string address = cities[randThisTime % cities.size()]; |
|
|
|
std::string age = std::to_string(std::abs(randThisTime) % AGE_RANGE); |
|
|
|
FieldArray fields = { |
|
|
|
{"name", name}, |
|
|
|
{"address", address}, |
|
|
|
{"age", age} |
|
|
|
}; |
|
|
|
if (address == "Shanghai") { |
|
|
|
shanghaiKeys.insert(key); |
|
|
|
} |
|
|
|
if (age == "20") { |
|
|
|
age20Keys.insert(key); |
|
|
|
} |
|
|
|
Status s = db->PutFields(WriteOptions(), key, fields); |
|
|
|
ASSERT_TRUE(s.ok()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//并发时不一定能读到,加个参数控制
|
|
|
|
void GetFieldData(FieldDB *db, bool allowNotFound, int seed = 0) { |
|
|
|
std::cout << "-------getting-------" << std::endl; |
|
|
|
ReadOptions readOptions; |
|
|
|
int key_num = data_size / value_size; |
|
|
|
|
|
|
|
// 点查
|
|
|
|
std::mt19937 rng(seed); |
|
|
|
for (int i = 0; i < 100; i++) { |
|
|
|
int randThisTime = rng(); |
|
|
|
int key_ = std::abs(randThisTime) % key_num + 1; |
|
|
|
std::string key = std::to_string(key_); |
|
|
|
FieldArray fields_ret; |
|
|
|
Status s = db->GetFields(readOptions, key, &fields_ret); |
|
|
|
if (!allowNotFound){ //必须读到
|
|
|
|
// if (!s.ok()){
|
|
|
|
// std::cout << key << std::endl;
|
|
|
|
// }
|
|
|
|
ASSERT_TRUE(s.ok()); |
|
|
|
} else { //不必须读到,但只要读到address必须正确
|
|
|
|
if(s.IsNotFound()) continue; |
|
|
|
} |
|
|
|
for (const Field& pairs : fields_ret) { |
|
|
|
if (pairs.first == "name"){ |
|
|
|
|
|
|
|
} else if (pairs.first == "address"){ |
|
|
|
std::string city = pairs.second; |
|
|
|
ASSERT_NE(std::find(cities.begin(), cities.end(), city), cities.end()); |
|
|
|
|
|
|
|
} else if (pairs.first == "age"){ |
|
|
|
int age = std::stoi(pairs.second); |
|
|
|
ASSERT_TRUE(age >= 0 && age < AGE_RANGE); |
|
|
|
|
|
|
|
} else assert(false); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void findKeysByCity(FieldDB *db) { |
|
|
|
std::cout << "-------getting field address-------" << std::endl; |
|
|
|
Field field = {"address", "Shanghai"}; |
|
|
|
std::vector<std::string> resKeys = db->FindKeysByField(field); |
|
|
|
//打印比较,因为shanghaikey可能被后写入的、其他address的key覆盖,打印出的后一个数应该小于前一个数
|
|
|
|
//如果随机种子相同,每次打印出的两个数也应该相同
|
|
|
|
std::cout << "address: " << shanghaiKeys.size() << " " << resKeys.size() << std::endl; |
|
|
|
for (const std::string &key : resKeys){ |
|
|
|
ASSERT_NE(std::find(shanghaiKeys.begin(), shanghaiKeys.end(), key), shanghaiKeys.end()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// haveIndex表明数据库有没有该索引(address)
|
|
|
|
void findKeysByCityIndex(FieldDB *db, bool haveIndex) { |
|
|
|
std::cout << "-------getting field address by index-------" << std::endl; |
|
|
|
Field field = {"address", "Shanghai"}; |
|
|
|
Status s; |
|
|
|
std::vector<std::string> resKeys = db->QueryByIndex(field, &s); |
|
|
|
if (haveIndex) ASSERT_TRUE(s.ok()); |
|
|
|
else { |
|
|
|
ASSERT_TRUE(s.IsNotFound()); |
|
|
|
return; |
|
|
|
} |
|
|
|
std::cout << "address: " << shanghaiKeys.size() << " " << resKeys.size() << std::endl;//打印比较
|
|
|
|
for (const std::string &key : resKeys){ |
|
|
|
ASSERT_NE(std::find(shanghaiKeys.begin(), shanghaiKeys.end(), key), shanghaiKeys.end()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void findKeysByAgeIndex(FieldDB *db, bool haveIndex) { |
|
|
|
std::cout << "-------getting field age by index-------" << std::endl; |
|
|
|
Field field = {"age", "20"}; |
|
|
|
Status s; |
|
|
|
std::vector<std::string> resKeys = db->QueryByIndex(field, &s); |
|
|
|
if (haveIndex) ASSERT_TRUE(s.ok()); |
|
|
|
else { |
|
|
|
ASSERT_TRUE(s.IsNotFound()); |
|
|
|
return; |
|
|
|
} |
|
|
|
std::cout << "age: " << age20Keys.size() << " " << resKeys.size() << std::endl; |
|
|
|
for (const std::string &key : resKeys){ |
|
|
|
ASSERT_NE(std::find(age20Keys.begin(), age20Keys.end(), key), age20Keys.end()); |
|
|
|
} |
|
|
|
} |