// ----------------------------------------------------------------------
// File: redis-parser.cc
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* quarkdb - a redis-like highly available key-value store *
* Copyright (C) 2016 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "redis/Transaction.hh"
#include "utils/Macros.hh"
#include "RedisParser.hh"
#include
using namespace quarkdb;
class Redis_Parser : public ::testing::Test {
protected:
virtual void SetUp() {
parser = new RedisParser(&link);
}
virtual void TearDown() {
delete parser;
}
void simulateBadConnection(const std::string &str, size_t bytes) {
size_t i = 0;
while(i + bytes < str.size()) {
ASSERT_EQ(parser->fetch(request, true), 0);
link.Send(str.c_str()+i, bytes);
i += bytes;
}
// send any left-over bytes
ASSERT_EQ(parser->fetch(request, true), 0);
link.Send(str.c_str()+i, str.size()-i);
}
void simulateMany(const std::string &str, RedisRequest &valid, size_t bytes) {
for(size_t i = 1; i < bytes; i++) {
ASSERT_EQ(parser->fetch(request, true), 0);
simulateBadConnection(str, i);
ASSERT_EQ(parser->fetch(request, true), 1);
ASSERT_EQ(request, valid);
}
ASSERT_EQ(parser->fetch(request, true), 0);
}
Link link;
RedisParser *parser;
RedisRequest request;
};
TEST_F(Redis_Parser, T1) {
ASSERT_EQ(parser->fetch(request, true), 0);
link.Send("*2\r\n$3\r\nget\r\n$3\r\nabc\r\n*3\r\n$3\r\nset\r\n$3\r\nabc\r\n$5\r\nhello\r\n");
ASSERT_EQ(parser->fetch(request, true), 1);
ASSERT_EQ(request.size(), (size_t) 2);
ASSERT_EQ(request[0], "get");
ASSERT_EQ(request[1], "abc");
request.clear();
ASSERT_EQ(parser->fetch(request, true), 1);
ASSERT_EQ(request.size(), (size_t) 3);
ASSERT_EQ(request[0], "set");
ASSERT_EQ(request[1], "abc");
ASSERT_EQ(request[2], "hello");
}
TEST_F(Redis_Parser, ZeroSizedString) {
ASSERT_EQ(parser->fetch(request, true), 0);
link.Send("*3\r\n$3\r\nset\r\n$0\r\n\r\n$3\r\nabc\r\n");
ASSERT_EQ(parser->fetch(request, true), -2);
}
TEST_F(Redis_Parser, T2) {
std::string str("*2\r\n$3\r\nget\r\n$3\r\nabc\r\n");
RedisRequest valid = {"get", "abc"};
ASSERT_EQ(valid.toPrintableString(), "\"get\" \"abc\"");
simulateMany(str, valid, 10);
str = "*3\r\n$3\r\nset\r\n$4\r\nabcd\r\n$5\r\n12345\r\n";
valid = {"set", "abcd", "12345"};
simulateMany(str, valid, 10);
// test two-digit integers
str = "*3\r\n$3\r\nset\r\n$15\r\nthis_key_is_big\r\n$17\r\nthis_value_is_big\r\n";
valid = {"set", "this_key_is_big", "this_value_is_big"};
simulateMany(str, valid, 10);
}
TEST(RedisRequest, TransactionToPrintableString) {
Transaction tx;
tx.emplace_back("set", "aaa", "bbb");
tx.emplace_back("get", "qwe", "rty");
RedisRequest req { "tx_readwrite", tx.serialize(), "phantom" };
ASSERT_EQ(req.toPrintableString(),
"TX_READWRITE (phantom), size 2\n"
" --- 1) \"set\" \"aaa\" \"bbb\"\n"
" --- 2) \"get\" \"qwe\" \"rty\""
);
}
TEST_F(Redis_Parser, T3) {
// test bogus data
link.Send("hello there\r\n");
ASSERT_LT(parser->fetch(request, true), 0);
}
TEST_F(Redis_Parser, T4) {
// bad integer
link.Send("*lol\r\n");
ASSERT_LT(parser->fetch(request, true), 0);
}
TEST_F(Redis_Parser, T5) {
// wrong string size
link.Send("*1\r\n$5\r\naaa\r\n");
ASSERT_LE(parser->fetch(request, true), 0);
}
TEST_F(Redis_Parser, T6) {
// bad string length integer
link.Send("*1\r\n$asdf\r\n");
ASSERT_LT(parser->fetch(request, true), 0);
}
TEST_F(Redis_Parser, T7) {
// corrupted \r\n
link.Send("*1\r\n$3abc\n\n");
ASSERT_LT(parser->fetch(request, true), 0);
}
TEST_F(Redis_Parser, T8) {
link.Send("*1\n\nabc");
ASSERT_LT(parser->fetch(request, true), 0);
}