Skip to content

Commit

Permalink
Refactor: use MemcachedConnection in testapp_topkeys.cc
Browse files Browse the repository at this point in the history
Change-Id: Ie593cb50b894d7974ce4d055ad07a738fd6390cb
Reviewed-on: http://review.couchbase.org/c/kv_engine/+/149668
Tested-by: Build Bot <build@couchbase.com>
Reviewed-by: Richard de Mellow <richard.demellow@couchbase.com>
  • Loading branch information
trondn committed Mar 29, 2021
1 parent f4778b1 commit c182f92
Showing 1 changed file with 57 additions and 138 deletions.
195 changes: 57 additions & 138 deletions tests/testapp/testapp_topkeys.cc
Expand Up @@ -28,102 +28,44 @@ class McdTopkeysTest : public McdTestappTest {};
* Returns the current access count of the test key ("someval") as an integer
* via the old string format.
*/
int get_topkeys_legacy_value(const std::string& wanted_key) {
BinprotGenericCommand st(ClientOpcode::Stat, "topkeys");
std::vector<uint8_t> blob;
st.encode(blob);
safe_send(blob);

// We expect a variable number of response packets (one per top key);
// take them all off the wire, recording the one for our key which we
// parse at the end.
std::string value;
while (true) {
if (!safe_recv_packet(blob)) {
ADD_FAILURE() << "Failed to receive topkeys packet";
return -1;
}
auto& response = *reinterpret_cast<Response*>(blob.data());
mcbp_validate_response_header(
response, ClientOpcode::Stat, Status::Success);

auto k = response.getKey();
// A packet with key length zero indicates end of the stats.
if (k.empty()) {
break;
}
const auto key =
std::string{reinterpret_cast<const char*>(k.data()), k.size()};
if (key == wanted_key) {
// Got our key. Save the value to one side; and finish consuming
// the STAT reponse packets.
EXPECT_TRUE(value.empty())
<< "Unexpectedly found a second topkey for wanted key '"
<< wanted_key;

auto val = response.getValue();
EXPECT_FALSE(val.empty());
value = std::string{reinterpret_cast<const char*>(val.data()),
val.size()};
}
}

if (!value.empty()) {
// Extract the 'get_hits' stat (which actually the aggregate of all
// operations now).
const std::string token("get_hits=");
auto pos = value.find(token);
EXPECT_NE(std::string::npos, pos)
<< "Failed to locate '" << token << "' substring in topkey '"
<< wanted_key << "' value '" << value << "'";

// Move iterator to the other side of the equals sign (the value) and
// erase before that point.
pos += token.size();
value.erase(0, pos);

return std::stoi(value);
} else {
// If we got here then we failed to find the given key.
return 0;
}
int get_topkeys_legacy_value(MemcachedConnection& conn,
const std::string& wanted_key) {
int ret = 0;
conn.stats(
[&ret, &wanted_key](const std::string& k, const std::string& v) {
if (k == wanted_key) {
// Extract the 'get_hits' stat (which actually the aggregate
// of all operations now).
auto value = v;
const std::string token("get_hits=");
auto pos = value.find(token);
EXPECT_NE(std::string::npos, pos)
<< "Failed to locate '" << token
<< "' substring in topkey '" << wanted_key
<< "' value '" << value << "'";
// Move iterator to the other side of the equals sign (the
// value) and erase before that point.
pos += token.size();
value.erase(0, pos);
ret = std::stoi(value);
}
},
"topkeys");
return ret;
}

/**
* Accesses the current value of the key via the JSON formatted topkeys return.
* @return True if the specified key was found (and sets count to the
* keys' access count) or false if not found.
*/
bool get_topkeys_json_value(const std::string& key, int& count) {
BinprotGenericCommand st(ClientOpcode::Stat, "topkeys_json");
std::vector<uint8_t> blob;
st.encode(blob);
safe_send(blob);

// Expect 1 valid packet followed by 1 null
if (!safe_recv_packet(blob)) {
ADD_FAILURE() << "Failed to recv topkeys_json response";
return false;
}
auto& response = *reinterpret_cast<Response*>(blob.data());
mcbp_validate_response_header(
response, ClientOpcode::Stat, Status::Success);

EXPECT_NE(0, response.getKeylen());
auto val = response.getValue();
EXPECT_FALSE(val.empty());
const std::string value(reinterpret_cast<const char*>(val.data()),
val.size());

// Consume NULL stats packet.
if (!safe_recv_packet(blob)) {
ADD_FAILURE() << "Failed to recv null stats packet";
return false;
}
response = *reinterpret_cast<Response*>(blob.data());
mcbp_validate_response_header(
response, ClientOpcode::Stat, Status::Success);
EXPECT_EQ(0, response.getKeylen());
bool get_topkeys_json_value(MemcachedConnection& conn,
const std::string& key,
int& count) {
std::string value;
conn.stats([&value](const std::string,
const std::string& v) { value.assign(v); },
"topkeys_json");

// Check for response string
auto json = nlohmann::json::parse(value);
Expand All @@ -146,90 +88,66 @@ bool get_topkeys_json_value(const std::string& key, int& count) {
* Set a key a number of times and assert that the return value matches the
* change after the number of set operations.
*/
static void test_set_topkeys(const std::string& key, const int operations) {
static void test_set_topkeys(MemcachedConnection& conn,
const std::string& key,
const int operations) {
// In theory we should start with no record of a key; but there's no
// explicit way to clear topkeys; and a previous test run against the same
// memcached instance may have used the same key.
// Therefore for robustness don't assume the key doesn't exist; and fetch
// the initial count.
int initial_count = 0;
get_topkeys_json_value(key, initial_count);

BinprotMutationCommand mut;
mut.setMutationType(MutationType::Set);
mut.setKey(key);
std::vector<uint8_t> set_command;
mut.encode(set_command);
get_topkeys_json_value(conn, key, initial_count);

// Send CMD_SET for current key 'sum' number of times (and validate
// response).
for (int ii = 0; ii < operations; ii++) {
safe_send(set_command);
std::vector<uint8_t> blob;
ASSERT_TRUE(safe_recv_packet(blob));
mcbp_validate_response_header(*reinterpret_cast<Response*>(blob.data()),
ClientOpcode::Set,
Status::Success);
conn.store(key, Vbid{0}, key);
}

EXPECT_EQ(initial_count + operations, get_topkeys_legacy_value(key));
EXPECT_EQ(initial_count + operations, get_topkeys_legacy_value(conn, key));
int json_value = 0;
EXPECT_TRUE(get_topkeys_json_value(key, json_value));
EXPECT_TRUE(get_topkeys_json_value(conn, key, json_value));
EXPECT_EQ(initial_count + operations, json_value);
}

/**
* Get a key a number of times and assert that the return value matches the
* change after the number of get operations.
*/
static void test_get_topkeys(const std::string& key, int operations) {
static void test_get_topkeys(MemcachedConnection& conn,
const std::string& key,
int operations) {
int initial_count = 0;
ASSERT_TRUE(get_topkeys_json_value(key, initial_count));

BinprotGenericCommand get(ClientOpcode::Get, key);
std::vector<uint8_t> get_command;
get.encode(get_command);
ASSERT_TRUE(get_topkeys_json_value(conn, key, initial_count));

for (int ii = 0; ii < operations; ii++) {
safe_send(get_command);
std::vector<uint8_t> buffer;
safe_recv_packet(buffer);
mcbp_validate_response_header(
*reinterpret_cast<Response*>(buffer.data()),
ClientOpcode::Get,
Status::Success);
conn.get(key, Vbid{0});
}

const int expected_count = initial_count + operations;
EXPECT_EQ(expected_count, get_topkeys_legacy_value(key))
EXPECT_EQ(expected_count, get_topkeys_legacy_value(conn, key))
<< "Unexpected topkeys legacy count for key:" << key;
int json_value = 0;
EXPECT_TRUE(get_topkeys_json_value(key, json_value));
EXPECT_TRUE(get_topkeys_json_value(conn, key, json_value));
EXPECT_EQ(expected_count, json_value);
}

/**
* Delete a key and assert that the return value matches the change
* after the delete operation.
*/
static void test_delete_topkeys(const std::string& key) {
static void test_delete_topkeys(MemcachedConnection& conn,
const std::string& key) {
int initial_count = 0;
ASSERT_TRUE(get_topkeys_json_value(key, initial_count));

BinprotGenericCommand cmd(ClientOpcode::Delete, key);
std::vector<uint8_t> blob;
cmd.encode(blob);
safe_send(blob);
ASSERT_TRUE(get_topkeys_json_value(conn, key, initial_count));

ASSERT_TRUE(safe_recv_packet(blob));
mcbp_validate_response_header(*reinterpret_cast<Response*>(blob.data()),
ClientOpcode::Delete,
Status::Success);
conn.remove(key, Vbid{0});

EXPECT_EQ(initial_count + 1, get_topkeys_legacy_value(key))
EXPECT_EQ(initial_count + 1, get_topkeys_legacy_value(conn, key))
<< "Unexpected topkeys legacy count for key:" << key;
int json_value = 0;
EXPECT_TRUE(get_topkeys_json_value(key, json_value));
EXPECT_TRUE(get_topkeys_json_value(conn, key, json_value));
EXPECT_EQ(initial_count + 1, json_value);
}

Expand All @@ -239,13 +157,14 @@ static void test_delete_topkeys(const std::string& key) {
*/
TEST_P(McdTopkeysTest, test_topkeys) {
/* Perform sets on a few different keys. */
test_set_topkeys("key1", 1);
test_set_topkeys("key2", 2);
test_set_topkeys("key3", 3);
auto& conn = getConnection();
test_set_topkeys(conn, "key1", 1);
test_set_topkeys(conn, "key2", 2);
test_set_topkeys(conn, "key3", 3);

test_get_topkeys("key1", 10);
test_get_topkeys(conn, "key1", 10);

test_delete_topkeys("key1");
test_delete_topkeys(conn, "key1");
}

INSTANTIATE_TEST_SUITE_P(
Expand Down

0 comments on commit c182f92

Please sign in to comment.