memgraph/tests/unit/bolt_encoder.cpp
Teon Banek 9f460914ed Separate distributed implementation of GraphDbAccessor
Summary:
GraphDbAccessor is now constructed only through GraphDb. This allows the
concrete GraphDb to instantiate a concrete GraphDbAccessor. This allows
us to use virtual calls, so that the implementation may be kept
separate. The major downside of doing things this way is heap allocation
of GraphDbAccessor. In case it turns out to be a real performance
issues, another solution with pointer to static implementation may be
used.

InsertVertexIntoRemote is now a non-member function, which reduces
coupling. It made no sense for it to be member function because it used
only the public parts of GraphDbAccessor.

Reviewers: msantl, mtomic, mferencevic

Reviewed By: msantl

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1504
2018-07-26 09:16:39 +02:00

259 lines
8.0 KiB
C++

#include "bolt_common.hpp"
#include "bolt_testdata.hpp"
#include "communication/bolt/v1/encoder/encoder.hpp"
#include "database/graph_db.hpp"
#include "database/graph_db_accessor.hpp"
#include "glue/conversion.hpp"
using communication::bolt::Value;
/**
* TODO (mferencevic): document
*/
constexpr const int SIZE = 131072;
uint8_t data[SIZE];
uint64_t GetBigEndianInt(std::vector<uint8_t> &v, uint8_t len,
uint8_t offset = 1) {
uint64_t ret = 0;
v.erase(v.begin(), v.begin() + offset);
for (int i = 0; i < len; ++i) {
ret <<= 8;
ret += v[i];
}
v.erase(v.begin(), v.begin() + len);
return ret;
}
void CheckTypeSize(std::vector<uint8_t> &v, int typ, uint64_t size) {
uint64_t len;
if ((v[0] & 0xF0) == type_tiny_magic[typ]) {
len = v[0] & 0x0F;
v.erase(v.begin(), v.begin() + 1);
} else if (v[0] == type_8_magic[typ]) {
len = GetBigEndianInt(v, 1);
} else if (v[0] == type_16_magic[typ]) {
len = GetBigEndianInt(v, 2);
} else if (v[0] == type_32_magic[typ]) {
len = GetBigEndianInt(v, 4);
} else {
FAIL() << "Got wrong marker!";
}
ASSERT_EQ(len, size);
}
void CheckInt(std::vector<uint8_t> &output, int64_t value) {
TestOutputStream output_stream;
TestBuffer encoder_buffer(output_stream);
communication::bolt::BaseEncoder<TestBuffer> bolt_encoder(encoder_buffer);
std::vector<uint8_t> &encoded = output_stream.output;
bolt_encoder.WriteInt(value);
CheckOutput(output, encoded.data(), encoded.size(), false);
}
void CheckRecordHeader(std::vector<uint8_t> &v, uint64_t size) {
CheckOutput(v, (const uint8_t *)"\xB1\x71", 2, false);
CheckTypeSize(v, LIST, size);
}
TestOutputStream output_stream;
TestBuffer encoder_buffer(output_stream);
communication::bolt::Encoder<TestBuffer> bolt_encoder(encoder_buffer);
std::vector<uint8_t> &output = output_stream.output;
TEST(BoltEncoder, NullAndBool) {
output.clear();
std::vector<Value> vals;
vals.push_back(Value());
vals.push_back(Value(true));
vals.push_back(Value(false));
bolt_encoder.MessageRecord(vals);
CheckRecordHeader(output, 3);
CheckOutput(output, (const uint8_t *)"\xC0\xC3\xC2", 3);
}
TEST(BoltEncoder, Int) {
int N = 28;
output.clear();
std::vector<Value> vals;
for (int i = 0; i < N; ++i) vals.push_back(Value(int_decoded[i]));
bolt_encoder.MessageRecord(vals);
CheckRecordHeader(output, N);
for (int i = 0; i < N; ++i)
CheckOutput(output, int_encoded[i], int_encoded_len[i], false);
CheckOutput(output, nullptr, 0);
}
TEST(BoltEncoder, Double) {
int N = 4;
output.clear();
std::vector<Value> vals;
for (int i = 0; i < N; ++i) vals.push_back(Value(double_decoded[i]));
bolt_encoder.MessageRecord(vals);
CheckRecordHeader(output, N);
for (int i = 0; i < N; ++i) CheckOutput(output, double_encoded[i], 9, false);
CheckOutput(output, nullptr, 0);
}
TEST(BoltEncoder, String) {
output.clear();
std::vector<Value> vals;
for (uint64_t i = 0; i < sizes_num; ++i)
vals.push_back(Value(std::string((const char *)data, sizes[i])));
bolt_encoder.MessageRecord(vals);
CheckRecordHeader(output, vals.size());
for (uint64_t i = 0; i < sizes_num; ++i) {
CheckTypeSize(output, STRING, sizes[i]);
CheckOutput(output, data, sizes[i], false);
}
CheckOutput(output, nullptr, 0);
}
TEST(BoltEncoder, List) {
output.clear();
std::vector<Value> vals;
for (uint64_t i = 0; i < sizes_num; ++i) {
std::vector<Value> val;
for (uint64_t j = 0; j < sizes[i]; ++j)
val.push_back(Value(std::string((const char *)&data[j], 1)));
vals.push_back(Value(val));
}
bolt_encoder.MessageRecord(vals);
CheckRecordHeader(output, vals.size());
for (uint64_t i = 0; i < sizes_num; ++i) {
CheckTypeSize(output, LIST, sizes[i]);
for (uint64_t j = 0; j < sizes[i]; ++j) {
CheckTypeSize(output, STRING, 1);
CheckOutput(output, &data[j], 1, false);
}
}
CheckOutput(output, nullptr, 0);
}
TEST(BoltEncoder, Map) {
output.clear();
std::vector<Value> vals;
uint8_t buff[10];
for (int i = 0; i < sizes_num; ++i) {
std::map<std::string, Value> val;
for (int j = 0; j < sizes[i]; ++j) {
sprintf((char *)buff, "%05X", j);
std::string tmp((char *)buff, 5);
val.insert(std::make_pair(tmp, Value(tmp)));
}
vals.push_back(Value(val));
}
bolt_encoder.MessageRecord(vals);
CheckRecordHeader(output, vals.size());
for (int i = 0; i < sizes_num; ++i) {
CheckTypeSize(output, MAP, sizes[i]);
for (int j = 0; j < sizes[i]; ++j) {
sprintf((char *)buff, "%05X", j);
CheckTypeSize(output, STRING, 5);
CheckOutput(output, buff, 5, false);
CheckTypeSize(output, STRING, 5);
CheckOutput(output, buff, 5, false);
}
}
CheckOutput(output, nullptr, 0);
}
TEST(BoltEncoder, VertexAndEdge) {
output.clear();
// create vertex
database::SingleNode db;
auto db_accessor = db.Access();
auto va1 = db_accessor->InsertVertex();
auto va2 = db_accessor->InsertVertex();
auto l1 = db_accessor->Label("label1");
auto l2 = db_accessor->Label("label2");
va1.add_label(l1);
va1.add_label(l2);
auto p1 = db_accessor->Property("prop1");
auto p2 = db_accessor->Property("prop2");
PropertyValue pv1(12), pv2(200);
va1.PropsSet(p1, pv1);
va1.PropsSet(p2, pv2);
// create edge
auto et = db_accessor->EdgeType("edgetype");
auto ea = db_accessor->InsertEdge(va1, va2, et);
auto p3 = db_accessor->Property("prop3");
auto p4 = db_accessor->Property("prop4");
PropertyValue pv3(42), pv4(1234);
ea.PropsSet(p3, pv3);
ea.PropsSet(p4, pv4);
// check everything
std::vector<Value> vals;
vals.push_back(glue::ToBoltValue(va1));
vals.push_back(glue::ToBoltValue(va2));
vals.push_back(glue::ToBoltValue(ea));
bolt_encoder.MessageRecord(vals);
// The vertexedge_encoded testdata has hardcoded zeros for IDs,
// and Memgraph now encodes IDs so we need to check the output
// part by part.
CheckOutput(output, vertexedge_encoded, 5, false);
CheckInt(output, va1.gid());
CheckOutput(output, vertexedge_encoded + 6, 34, false);
CheckInt(output, va2.gid());
CheckOutput(output, vertexedge_encoded + 41, 4, false);
CheckInt(output, ea.gid());
CheckInt(output, va1.gid());
CheckInt(output, va2.gid());
CheckOutput(output, vertexedge_encoded + 48, 26);
}
TEST(BoltEncoder, BoltV1ExampleMessages) {
// this test checks example messages from: http://boltprotocol.org/v1/
output.clear();
// record message
std::vector<Value> rvals;
for (int i = 1; i < 4; ++i) rvals.push_back(Value(i));
bolt_encoder.MessageRecord(rvals);
CheckOutput(output, (const uint8_t *)"\xB1\x71\x93\x01\x02\x03", 6);
// success message
std::string sv1("name"), sv2("age"), sk("fields");
std::vector<Value> svec;
svec.push_back(Value(sv1));
svec.push_back(Value(sv2));
Value slist(svec);
std::map<std::string, Value> svals;
svals.insert(std::make_pair(sk, slist));
bolt_encoder.MessageSuccess(svals);
CheckOutput(output,
(const uint8_t *) "\xB1\x70\xA1\x86\x66\x69\x65\x6C\x64\x73\x92\x84\x6E\x61\x6D\x65\x83\x61\x67\x65",
20);
// failure message
std::string fv1("Neo.ClientError.Statement.SyntaxError"),
fv2("Invalid syntax.");
std::string fk1("code"), fk2("message");
Value ftv1(fv1), ftv2(fv2);
std::map<std::string, Value> fvals;
fvals.insert(std::make_pair(fk1, ftv1));
fvals.insert(std::make_pair(fk2, ftv2));
bolt_encoder.MessageFailure(fvals);
CheckOutput(output,
(const uint8_t *) "\xB1\x7F\xA2\x84\x63\x6F\x64\x65\xD0\x25\x4E\x65\x6F\x2E\x43\x6C\x69\x65\x6E\x74\x45\x72\x72\x6F\x72\x2E\x53\x74\x61\x74\x65\x6D\x65\x6E\x74\x2E\x53\x79\x6E\x74\x61\x78\x45\x72\x72\x6F\x72\x87\x6D\x65\x73\x73\x61\x67\x65\x8F\x49\x6E\x76\x61\x6C\x69\x64\x20\x73\x79\x6E\x74\x61\x78\x2E",
71);
// ignored message
bolt_encoder.MessageIgnored();
CheckOutput(output, (const uint8_t *)"\xB0\x7E", 2);
}
int main(int argc, char **argv) {
InitializeData(data, SIZE);
google::InitGoogleLogging(argv[0]);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}