MB-20054: Regression test - bucket is deleted with DCPBackfill running
[ep-engine.git] / tests / module_tests / evp_store_test.cc
1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2016 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 EventuallyPersistentStore class.
20  *
21  * Note that these test do *not* have the normal Tasks running (BGFetcher,
22  * flusher etc) as we do not initialise EPEngine. This means that such tasks
23  * need to be manually run. This can be very helpful as it essentially gives us
24  * synchronous control of EPStore.
25  */
26
27 #include "evp_store_test.h"
28
29 #include "bgfetcher.h"
30 #include "checkpoint.h"
31 #include "checkpoint_remover.h"
32 #include "connmap.h"
33 #include "ep_engine.h"
34 #include "flusher.h"
35 #include "tapthrottle.h"
36 #include "../mock/mock_dcp_producer.h"
37
38 #include "programs/engine_testapp/mock_server.h"
39 #include <platform/dirutils.h>
40
41 SynchronousEPEngine::SynchronousEPEngine(const std::string& extra_config)
42     : EventuallyPersistentEngine(get_mock_server_api) {
43     maxFailoverEntries = 1;
44
45     EventuallyPersistentEngine::loggerApi = get_mock_server_api()->log;
46
47     // Merge any extra config into the main configuration.
48     if (extra_config.size() > 0) {
49         if (!configuration.parseConfiguration(extra_config.c_str(),
50                                               serverApi)) {
51             throw std::invalid_argument("Unable to parse config string: " +
52                                         extra_config);
53         }
54     }
55
56     // workload is needed by EPStore's constructor (to construct the
57     // VBucketMap).
58     workload = new WorkLoadPolicy(/*workers*/1, /*shards*/1);
59
60     // dcpConnMap_ is needed by EPStore's constructor.
61     dcpConnMap_ = new DcpConnMap(*this);
62
63     // tapConnMap is needed by queueDirty.
64     tapConnMap = new TapConnMap(*this);
65
66     // checkpointConfig is needed by CheckpointManager (via EPStore).
67     checkpointConfig = new CheckpointConfig(*this);
68
69     // tapConfig is needed by doTapStats().
70     tapConfig = new TapConfig(*this);
71
72     // tapThrottle is needed by doEngineStats().
73     tapThrottle = new TapThrottle(configuration, stats);
74 }
75
76 void SynchronousEPEngine::setEPStore(EventuallyPersistentStore* store) {
77     cb_assert(epstore == NULL);
78     epstore = store;
79 }
80
81 MockEPStore::MockEPStore(EventuallyPersistentEngine &theEngine)
82     : EventuallyPersistentStore(theEngine) {
83     // Perform a limited set of setup (normally done by EPStore::initialize) -
84     // enough such that objects which are assumed to exist are present.
85
86     // Create the closed checkpoint removed task. Note we do _not_ schedule
87     // it, unlike EPStore::initialize
88     chkTask = new ClosedUnrefCheckpointRemoverTask
89             (&engine, stats, theEngine.getConfiguration().getChkRemoverStime());
90 }
91
92 VBucketMap& MockEPStore::getVbMap() {
93     return vbMap;
94 }
95
96 /* Mock Task class. Doesn't actually run() or snooze() - they both do nothing.
97  */
98 class MockGlobalTask : public GlobalTask {
99 public:
100     MockGlobalTask(EventuallyPersistentEngine* e, const Priority &p)
101         : GlobalTask(e, p) {}
102
103     bool run() { return false; }
104     std::string getDescription() { return "MockGlobalTask"; }
105
106     void snooze(const double secs) {}
107 };
108
109 void EventuallyPersistentStoreTest::SetUp() {
110     // Paranoia - kill any existing files in case they are left over
111     // from a previous run.
112     CouchbaseDirectoryUtilities::rmrf(test_dbname);
113
114     // Add dbname to config string.
115     std::string config = config_string;
116     if (config.size() > 0) {
117         config += ";";
118     }
119     config += "dbname=" + std::string(test_dbname);
120
121     vbid = 0;
122
123     engine = new SynchronousEPEngine(config);
124     ObjectRegistry::onSwitchThread(engine);
125
126     store = new MockEPStore(*engine);
127     engine->setEPStore(store);
128
129     // Ensure that EPEngine is hold about necessary server callbacks
130     // (client disconnect, bucket delete).
131     engine->public_initializeEngineCallbacks();
132
133     // Need to initialize ep_real_time and friends.
134     initialize_time_functions(get_mock_server_api()->core);
135
136     cookie = create_mock_cookie();
137 }
138
139 void EventuallyPersistentStoreTest::TearDown() {
140     destroy_mock_cookie(cookie);
141     destroy_mock_event_callbacks();
142     if (engine) {
143         engine->getDcpConnMap().manageConnections();
144     }
145
146     // Need to have the current engine valid before deleting (this is what
147     // EvpDestroy does normally; however we have a smart ptr to the engine
148     // so must delete via that).
149     ObjectRegistry::onSwitchThread(engine);
150     delete engine;
151
152     // Shutdown the ExecutorPool singleton (initialized when we create
153     // an EventuallyPersistentStore object). Must happen after engine
154     // has been destroyed (to allow the tasks the engine has
155     // registered a chance to be unregistered).
156     ExecutorPool::shutdown();
157 }
158
159 void EventuallyPersistentStoreTest::store_item(uint16_t vbid,
160                                                const std::string& key,
161                                                const std::string& value) {
162     Item item(key.c_str(), key.size(), /*flags*/0, /*exp*/0, value.c_str(),
163               value.size());
164     item.setVBucketId(vbid);
165     EXPECT_EQ(ENGINE_SUCCESS, store->set(item, NULL));
166 }
167
168
169 //
170 // EPStoreEvictionTest disabled in 3.0.x backport - there's an unknown
171 // bug where onSwitchThread() ends up NULL, meaning that we eventually hit
172 // an assert and crash.
173 //
174
175
176 const char EventuallyPersistentStoreTest::test_dbname[] = "ep_engine_ep_unit_tests_db";