2017-03-22 22:53:30 +08:00
|
|
|
#include "bolt_common.hpp"
|
2017-04-06 20:30:04 +08:00
|
|
|
#include "bolt_testdata.hpp"
|
2017-03-22 22:53:30 +08:00
|
|
|
|
|
|
|
#include "communication/bolt/v1/encoder/encoder.hpp"
|
|
|
|
#include "database/graph_db.hpp"
|
|
|
|
#include "database/graph_db_accessor.hpp"
|
Extract communication to static library
Summary:
Session specifics have been move out of the Bolt `executing` state, and
are accessed via pure virtual Session type. Our server is templated on
the session and we are setting the concrete type, so there should be no
virtual call overhead. Abstract Session is used to indicate the
interface, this could have also been templated, but the explicit
interface definition makes it clearer.
Specific session implementation for running Memgraph is now implemented
in memgraph_bolt, which instantiates the concrete session type. This may
not be 100% appropriate place, but Memgraph specific session isn't
needed anywhere else.
Bolt/communication tests now use a dummy session and depend only on
communication, which significantly improves test run times.
All these changes make the communication a library which doesn't depend
on storage nor the database. Only shared connection points, which aren't
part of the base communication library are:
* glue/conversion -- which converts between storage and bolt types, and
* communication/result_stream_faker -- templated, but used in tests and query/repl
Depends on D1453
Reviewers: mferencevic, buda, mtomic, msantl
Reviewed By: mferencevic, mtomic
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D1456
2018-07-10 22:18:19 +08:00
|
|
|
#include "glue/conversion.hpp"
|
2017-04-10 18:22:48 +08:00
|
|
|
|
2018-07-24 21:11:18 +08:00
|
|
|
using communication::bolt::Value;
|
2017-03-22 22:53:30 +08:00
|
|
|
|
2017-03-28 18:42:04 +08:00
|
|
|
/**
|
|
|
|
* TODO (mferencevic): document
|
|
|
|
*/
|
|
|
|
|
2017-03-22 22:53:30 +08:00
|
|
|
constexpr const int SIZE = 131072;
|
|
|
|
uint8_t data[SIZE];
|
|
|
|
|
2017-06-21 17:29:13 +08:00
|
|
|
uint64_t GetBigEndianInt(std::vector<uint8_t> &v, uint8_t len,
|
|
|
|
uint8_t offset = 1) {
|
2017-05-03 20:16:56 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-03-28 18:42:04 +08:00
|
|
|
void CheckTypeSize(std::vector<uint8_t> &v, int typ, uint64_t size) {
|
2017-05-03 20:16:56 +08:00
|
|
|
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);
|
2017-03-22 22:53:30 +08:00
|
|
|
} else {
|
2017-05-03 20:16:56 +08:00
|
|
|
FAIL() << "Got wrong marker!";
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
2017-05-03 20:16:56 +08:00
|
|
|
ASSERT_EQ(len, size);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
2017-08-09 16:56:41 +08:00
|
|
|
void CheckInt(std::vector<uint8_t> &output, int64_t value) {
|
2018-03-23 23:32:17 +08:00
|
|
|
TestOutputStream output_stream;
|
|
|
|
TestBuffer encoder_buffer(output_stream);
|
2017-08-09 16:56:41 +08:00
|
|
|
communication::bolt::BaseEncoder<TestBuffer> bolt_encoder(encoder_buffer);
|
2018-03-23 23:32:17 +08:00
|
|
|
std::vector<uint8_t> &encoded = output_stream.output;
|
2017-08-09 16:56:41 +08:00
|
|
|
bolt_encoder.WriteInt(value);
|
|
|
|
CheckOutput(output, encoded.data(), encoded.size(), false);
|
|
|
|
}
|
|
|
|
|
2017-03-28 18:42:04 +08:00
|
|
|
void CheckRecordHeader(std::vector<uint8_t> &v, uint64_t size) {
|
|
|
|
CheckOutput(v, (const uint8_t *)"\xB1\x71", 2, false);
|
|
|
|
CheckTypeSize(v, LIST, size);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
2018-03-23 23:32:17 +08:00
|
|
|
TestOutputStream output_stream;
|
|
|
|
TestBuffer encoder_buffer(output_stream);
|
2017-03-28 18:42:04 +08:00
|
|
|
communication::bolt::Encoder<TestBuffer> bolt_encoder(encoder_buffer);
|
2018-03-23 23:32:17 +08:00
|
|
|
std::vector<uint8_t> &output = output_stream.output;
|
2017-03-22 22:53:30 +08:00
|
|
|
|
|
|
|
TEST(BoltEncoder, NullAndBool) {
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> vals;
|
|
|
|
vals.push_back(Value());
|
|
|
|
vals.push_back(Value(true));
|
|
|
|
vals.push_back(Value(false));
|
2017-03-22 22:53:30 +08:00
|
|
|
bolt_encoder.MessageRecord(vals);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckRecordHeader(output, 3);
|
|
|
|
CheckOutput(output, (const uint8_t *)"\xC0\xC3\xC2", 3);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoltEncoder, Int) {
|
|
|
|
int N = 28;
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> vals;
|
|
|
|
for (int i = 0; i < N; ++i) vals.push_back(Value(int_decoded[i]));
|
2017-03-22 22:53:30 +08:00
|
|
|
bolt_encoder.MessageRecord(vals);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckRecordHeader(output, N);
|
2017-03-22 22:53:30 +08:00
|
|
|
for (int i = 0; i < N; ++i)
|
2017-04-06 20:30:04 +08:00
|
|
|
CheckOutput(output, int_encoded[i], int_encoded_len[i], false);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckOutput(output, nullptr, 0);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoltEncoder, Double) {
|
|
|
|
int N = 4;
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> vals;
|
|
|
|
for (int i = 0; i < N; ++i) vals.push_back(Value(double_decoded[i]));
|
2017-03-22 22:53:30 +08:00
|
|
|
bolt_encoder.MessageRecord(vals);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckRecordHeader(output, N);
|
2017-04-06 20:30:04 +08:00
|
|
|
for (int i = 0; i < N; ++i) CheckOutput(output, double_encoded[i], 9, false);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckOutput(output, nullptr, 0);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoltEncoder, String) {
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> vals;
|
2017-03-28 18:42:04 +08:00
|
|
|
for (uint64_t i = 0; i < sizes_num; ++i)
|
2018-07-24 21:11:18 +08:00
|
|
|
vals.push_back(Value(std::string((const char *)data, sizes[i])));
|
2017-03-22 22:53:30 +08:00
|
|
|
bolt_encoder.MessageRecord(vals);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckRecordHeader(output, vals.size());
|
|
|
|
for (uint64_t i = 0; i < sizes_num; ++i) {
|
|
|
|
CheckTypeSize(output, STRING, sizes[i]);
|
|
|
|
CheckOutput(output, data, sizes[i], false);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckOutput(output, nullptr, 0);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoltEncoder, List) {
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> vals;
|
2017-03-28 18:42:04 +08:00
|
|
|
for (uint64_t i = 0; i < sizes_num; ++i) {
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> val;
|
2017-03-28 18:42:04 +08:00
|
|
|
for (uint64_t j = 0; j < sizes[i]; ++j)
|
2018-07-24 21:11:18 +08:00
|
|
|
val.push_back(Value(std::string((const char *)&data[j], 1)));
|
|
|
|
vals.push_back(Value(val));
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
bolt_encoder.MessageRecord(vals);
|
2017-03-28 18:42:04 +08:00
|
|
|
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);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
}
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckOutput(output, nullptr, 0);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoltEncoder, Map) {
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> vals;
|
2017-03-22 22:53:30 +08:00
|
|
|
uint8_t buff[10];
|
|
|
|
for (int i = 0; i < sizes_num; ++i) {
|
2018-07-24 21:11:18 +08:00
|
|
|
std::map<std::string, Value> val;
|
2017-03-22 22:53:30 +08:00
|
|
|
for (int j = 0; j < sizes[i]; ++j) {
|
2017-03-28 18:42:04 +08:00
|
|
|
sprintf((char *)buff, "%05X", j);
|
|
|
|
std::string tmp((char *)buff, 5);
|
2018-07-24 21:11:18 +08:00
|
|
|
val.insert(std::make_pair(tmp, Value(tmp)));
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
2018-07-24 21:11:18 +08:00
|
|
|
vals.push_back(Value(val));
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
bolt_encoder.MessageRecord(vals);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckRecordHeader(output, vals.size());
|
2017-03-22 22:53:30 +08:00
|
|
|
for (int i = 0; i < sizes_num; ++i) {
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckTypeSize(output, MAP, sizes[i]);
|
2017-03-22 22:53:30 +08:00
|
|
|
for (int j = 0; j < sizes[i]; ++j) {
|
2017-03-28 18:42:04 +08:00
|
|
|
sprintf((char *)buff, "%05X", j);
|
|
|
|
CheckTypeSize(output, STRING, 5);
|
|
|
|
CheckOutput(output, buff, 5, false);
|
|
|
|
CheckTypeSize(output, STRING, 5);
|
|
|
|
CheckOutput(output, buff, 5, false);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
}
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckOutput(output, nullptr, 0);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoltEncoder, VertexAndEdge) {
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
|
|
|
|
2017-03-22 22:53:30 +08:00
|
|
|
// create vertex
|
2018-01-12 22:17:04 +08:00
|
|
|
database::SingleNode db;
|
2018-07-26 15:08:21 +08:00
|
|
|
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");
|
2017-11-23 23:36:54 +08:00
|
|
|
va1.add_label(l1);
|
|
|
|
va1.add_label(l2);
|
2018-07-26 15:08:21 +08:00
|
|
|
auto p1 = db_accessor->Property("prop1");
|
|
|
|
auto p2 = db_accessor->Property("prop2");
|
2017-03-22 22:53:30 +08:00
|
|
|
PropertyValue pv1(12), pv2(200);
|
2017-11-23 23:36:54 +08:00
|
|
|
va1.PropsSet(p1, pv1);
|
|
|
|
va1.PropsSet(p2, pv2);
|
2017-03-22 22:53:30 +08:00
|
|
|
|
|
|
|
// create edge
|
2018-07-26 15:08:21 +08:00
|
|
|
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");
|
2017-03-22 22:53:30 +08:00
|
|
|
PropertyValue pv3(42), pv4(1234);
|
2017-11-23 23:36:54 +08:00
|
|
|
ea.PropsSet(p3, pv3);
|
|
|
|
ea.PropsSet(p4, pv4);
|
2017-03-22 22:53:30 +08:00
|
|
|
|
|
|
|
// check everything
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> vals;
|
|
|
|
vals.push_back(glue::ToBoltValue(va1));
|
|
|
|
vals.push_back(glue::ToBoltValue(va2));
|
|
|
|
vals.push_back(glue::ToBoltValue(ea));
|
2017-03-22 22:53:30 +08:00
|
|
|
bolt_encoder.MessageRecord(vals);
|
2017-08-09 16:56:41 +08:00
|
|
|
|
|
|
|
// 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);
|
2017-12-05 17:32:31 +08:00
|
|
|
CheckInt(output, va1.gid());
|
2017-08-09 16:56:41 +08:00
|
|
|
CheckOutput(output, vertexedge_encoded + 6, 34, false);
|
2017-12-05 17:32:31 +08:00
|
|
|
CheckInt(output, va2.gid());
|
2017-08-09 16:56:41 +08:00
|
|
|
CheckOutput(output, vertexedge_encoded + 41, 4, false);
|
2017-12-05 17:32:31 +08:00
|
|
|
CheckInt(output, ea.gid());
|
|
|
|
CheckInt(output, va1.gid());
|
|
|
|
CheckInt(output, va2.gid());
|
2017-08-09 16:56:41 +08:00
|
|
|
CheckOutput(output, vertexedge_encoded + 48, 26);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoltEncoder, BoltV1ExampleMessages) {
|
|
|
|
// this test checks example messages from: http://boltprotocol.org/v1/
|
|
|
|
|
2017-08-09 16:56:41 +08:00
|
|
|
output.clear();
|
|
|
|
|
2017-03-22 22:53:30 +08:00
|
|
|
// record message
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> rvals;
|
|
|
|
for (int i = 1; i < 4; ++i) rvals.push_back(Value(i));
|
2017-03-22 22:53:30 +08:00
|
|
|
bolt_encoder.MessageRecord(rvals);
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckOutput(output, (const uint8_t *)"\xB1\x71\x93\x01\x02\x03", 6);
|
2017-03-22 22:53:30 +08:00
|
|
|
|
|
|
|
// success message
|
|
|
|
std::string sv1("name"), sv2("age"), sk("fields");
|
2018-07-24 21:11:18 +08:00
|
|
|
std::vector<Value> svec;
|
|
|
|
svec.push_back(Value(sv1));
|
|
|
|
svec.push_back(Value(sv2));
|
|
|
|
Value slist(svec);
|
|
|
|
std::map<std::string, Value> svals;
|
2017-03-22 22:53:30 +08:00
|
|
|
svals.insert(std::make_pair(sk, slist));
|
|
|
|
bolt_encoder.MessageSuccess(svals);
|
2017-03-28 18:42:04 +08:00
|
|
|
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);
|
2017-03-22 22:53:30 +08:00
|
|
|
|
|
|
|
// failure message
|
2017-03-28 18:42:04 +08:00
|
|
|
std::string fv1("Neo.ClientError.Statement.SyntaxError"),
|
|
|
|
fv2("Invalid syntax.");
|
2017-03-22 22:53:30 +08:00
|
|
|
std::string fk1("code"), fk2("message");
|
2018-07-24 21:11:18 +08:00
|
|
|
Value ftv1(fv1), ftv2(fv2);
|
|
|
|
std::map<std::string, Value> fvals;
|
2017-03-22 22:53:30 +08:00
|
|
|
fvals.insert(std::make_pair(fk1, ftv1));
|
|
|
|
fvals.insert(std::make_pair(fk2, ftv2));
|
|
|
|
bolt_encoder.MessageFailure(fvals);
|
2017-03-28 18:42:04 +08:00
|
|
|
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);
|
2017-03-22 22:53:30 +08:00
|
|
|
|
|
|
|
// ignored message
|
|
|
|
bolt_encoder.MessageIgnored();
|
2017-03-28 18:42:04 +08:00
|
|
|
CheckOutput(output, (const uint8_t *)"\xB0\x7E", 2);
|
2017-03-22 22:53:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-28 18:42:04 +08:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
InitializeData(data, SIZE);
|
2017-06-21 17:29:13 +08:00
|
|
|
google::InitGoogleLogging(argv[0]);
|
2017-03-22 22:53:30 +08:00
|
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
return RUN_ALL_TESTS();
|
|
|
|
}
|