289255aeae6f1f57e20ca77d6e44c82d12b96226
[ep-engine.git] / tests / module_tests / stored_value_test.cc
1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2017 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17
18 /*
19  * Unit tests for the StoredValue class.
20  */
21
22 #include "config.h"
23
24 #include "hash_table.h"
25 #include "stats.h"
26 #include "stored_value_factories.h"
27 #include "tests/module_tests/test_helpers.h"
28
29 #include <gtest/gtest.h>
30
31 /**
32  * Test fixture for StoredValue tests. Type-parameterized to test both
33  * StoredValue and OrderedStoredValue.
34  */
35 template <typename Factory>
36 class ValueTest : public ::testing::Test {
37 public:
38     ValueTest()
39         : stats(),
40           factory(stats),
41           ht(stats, std::make_unique<Factory>(stats), /*size*/ 47, /*locks*/ 1),
42           item(make_item(0, makeStoredDocKey("key"), "value")) {
43     }
44
45     void SetUp() override {
46         // Create an initial stored value for testing - key length (3) and
47         // value length (5).
48         sv = factory(item, {}, ht);
49     }
50
51     /// Returns the number of bytes in the Fixed part of StoredValue
52     static size_t getFixedSize() {
53         return sizeof(typename Factory::value_type);
54     }
55
56     /// Allow testing access to StoredValue::getRequiredStorage
57     static size_t public_getRequiredStorage(const Item& item) {
58         return Factory::value_type::getRequiredStorage(item);
59     }
60
61 protected:
62     EPStats stats;
63     Factory factory;
64     HashTable ht;
65     Item item;
66     StoredValue::UniquePtr sv;
67 };
68
69 using ValueFactories =
70         ::testing::Types<StoredValueFactory, OrderedStoredValueFactory>;
71 TYPED_TEST_CASE(ValueTest, ValueFactories);
72
73 // Check that the size calculation methods return the expected sizes.
74
75 TYPED_TEST(ValueTest, getObjectSize) {
76     // Check the size are as expected: Fixed size of (Ordered)StoredValue, plus
77     // 3 bytes
78     // for 'key', 1 byte for length of key and 1 byte for StoredDocKey
79     // namespace.
80     EXPECT_EQ(this->getFixedSize() + /*key*/ 3 + /*len*/ 1 +
81                       /*namespace*/ 1,
82               this->sv->getObjectSize());
83 }
84
85 TYPED_TEST(ValueTest, metaDataSize) {
86     // Check metadata size reports correctly.
87     EXPECT_EQ(this->getFixedSize() + /*key*/ 3 + /*len*/ 1 +
88                       /*namespace*/ 1,
89               this->sv->metaDataSize());
90 }
91
92 TYPED_TEST(ValueTest, valuelen) {
93     // Check valuelen reports correctly.
94     EXPECT_EQ(/*value length*/ 5 + /*extmeta*/ 2, this->sv->valuelen())
95             << "valuelen() expected to be sum of raw value length + extended "
96                "meta";
97 }
98
99 TYPED_TEST(ValueTest, valuelenDeletedWithValue) {
100     // Check valuelen reports correctly for a StoredValue just marked delete
101     // (with xattrs deleted items can have value)
102     this->sv->markDeleted();
103     EXPECT_EQ(/*value length*/ 5 + /*extmeta*/ 2, this->sv->valuelen())
104             << "valuelen() expected to be sum of raw value length + extended "
105                "meta as we want to keep deleted body";
106 }
107
108 TYPED_TEST(ValueTest, valuelenDeletedWithoutValue) {
109     // Check valuelen reports correctly for a StoredValue logically delete
110     this->sv->del(this->ht);
111     EXPECT_EQ(0, this->sv->valuelen())
112             << "valuelen() expected to be 0 as we do not want to keep deleted "
113                "body";
114 }
115
116 TYPED_TEST(ValueTest, size) {
117     // Check size reports correctly.
118     EXPECT_EQ(this->getFixedSize() + /*key*/ 3 + /*len*/ 1 +
119                       /*namespace*/ 1 + /*valuelen*/ 5 + /*extmeta*/ 2,
120               this->sv->size());
121 }
122
123 TYPED_TEST(ValueTest, getRequiredStorage) {
124     EXPECT_EQ(this->sv->getObjectSize(),
125               this->public_getRequiredStorage(this->item))
126             << "Actual object size doesn't match what getRequiredStorage "
127                "predicted";
128 }
129
130 /// Check that StoredValue / OrderedStoredValue don't unexpectedly change in
131 /// size (we've carefully crafted them to be as efficient as possible).
132 TEST(StoredValueTest, expectedSize) {
133     EXPECT_EQ(56, sizeof(StoredValue))
134             << "Unexpected change in StoredValue fixed size";
135     auto item = make_item(0, makeStoredDocKey("k"), "v");
136     EXPECT_EQ(59, StoredValue::getRequiredStorage(item))
137             << "Unexpected change in StoredValue storage size for item: "
138             << item;
139 }
140
141 TEST(OrderedStoredValueTest, expectedSize) {
142     EXPECT_EQ(72, sizeof(OrderedStoredValue))
143             << "Unexpected change in OrderedStoredValue fixed size";
144     auto item = make_item(0, makeStoredDocKey("k"), "v");
145     EXPECT_EQ(75, OrderedStoredValue::getRequiredStorage(item))
146             << "Unexpected change in OrderedStoredValue storage size for item: "
147             << item;
148 }