]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/utilities/document/document_db_test.cc
build: use dgit for download target
[ceph.git] / ceph / src / rocksdb / utilities / document / document_db_test.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
2// This source code is licensed under both the GPLv2 (found in the
3// COPYING file in the root directory) and Apache 2.0 License
4// (found in the LICENSE.Apache file in the root directory).
7c673cae
FG
5
6#ifndef ROCKSDB_LITE
7
8#include <algorithm>
9
10#include "rocksdb/utilities/json_document.h"
11#include "rocksdb/utilities/document_db.h"
12
13#include "util/testharness.h"
14#include "util/testutil.h"
15
16namespace rocksdb {
17
18class DocumentDBTest : public testing::Test {
19 public:
20 DocumentDBTest() {
11fdf7f2 21 dbname_ = test::PerThreadDBPath("document_db_test");
7c673cae
FG
22 DestroyDB(dbname_, Options());
23 }
24 ~DocumentDBTest() {
25 delete db_;
26 DestroyDB(dbname_, Options());
27 }
28
29 void AssertCursorIDs(Cursor* cursor, std::vector<int64_t> expected) {
30 std::vector<int64_t> got;
31 while (cursor->Valid()) {
32 ASSERT_TRUE(cursor->Valid());
33 ASSERT_TRUE(cursor->document().Contains("_id"));
34 got.push_back(cursor->document()["_id"].GetInt64());
35 cursor->Next();
36 }
37 std::sort(expected.begin(), expected.end());
38 std::sort(got.begin(), got.end());
39 ASSERT_TRUE(got == expected);
40 }
41
42 // converts ' to ", so that we don't have to escape " all over the place
43 std::string ConvertQuotes(const std::string& input) {
44 std::string output;
45 for (auto x : input) {
46 if (x == '\'') {
47 output.push_back('\"');
48 } else {
49 output.push_back(x);
50 }
51 }
52 return output;
53 }
54
55 void CreateIndexes(std::vector<DocumentDB::IndexDescriptor> indexes) {
56 for (auto i : indexes) {
57 ASSERT_OK(db_->CreateIndex(WriteOptions(), i));
58 }
59 }
60
61 JSONDocument* Parse(const std::string& doc) {
62 return JSONDocument::ParseJSON(ConvertQuotes(doc).c_str());
63 }
64
65 std::string dbname_;
66 DocumentDB* db_;
67};
68
69TEST_F(DocumentDBTest, SimpleQueryTest) {
70 DocumentDBOptions options;
71 DocumentDB::IndexDescriptor index;
72 index.description = Parse("{\"name\": 1}");
73 index.name = "name_index";
74
75 ASSERT_OK(DocumentDB::Open(options, dbname_, {}, &db_));
76 CreateIndexes({index});
77 delete db_;
11fdf7f2 78 db_ = nullptr;
7c673cae
FG
79 // now there is index present
80 ASSERT_OK(DocumentDB::Open(options, dbname_, {index}, &db_));
11fdf7f2 81 assert(db_ != nullptr);
7c673cae
FG
82 delete index.description;
83
84 std::vector<std::string> json_objects = {
85 "{\"_id\': 1, \"name\": \"One\"}", "{\"_id\": 2, \"name\": \"Two\"}",
86 "{\"_id\": 3, \"name\": \"Three\"}", "{\"_id\": 4, \"name\": \"Four\"}"};
87
88 for (auto& json : json_objects) {
89 std::unique_ptr<JSONDocument> document(Parse(json));
90 ASSERT_TRUE(document.get() != nullptr);
91 ASSERT_OK(db_->Insert(WriteOptions(), *document));
92 }
93
94 // inserting a document with existing primary key should return failure
95 {
96 std::unique_ptr<JSONDocument> document(Parse(json_objects[0]));
97 ASSERT_TRUE(document.get() != nullptr);
98 Status s = db_->Insert(WriteOptions(), *document);
99 ASSERT_TRUE(s.IsInvalidArgument());
100 }
101
102 // find equal to "Two"
103 {
104 std::unique_ptr<JSONDocument> query(
105 Parse("[{'$filter': {'name': 'Two', '$index': 'name_index'}}]"));
106 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
107 AssertCursorIDs(cursor.get(), {2});
108 }
109
110 // find less than "Three"
111 {
112 std::unique_ptr<JSONDocument> query(Parse(
113 "[{'$filter': {'name': {'$lt': 'Three'}, '$index': "
114 "'name_index'}}]"));
115 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
116
117 AssertCursorIDs(cursor.get(), {1, 4});
118 }
119
120 // find less than "Three" without index
121 {
122 std::unique_ptr<JSONDocument> query(
123 Parse("[{'$filter': {'name': {'$lt': 'Three'} }}]"));
124 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
125 AssertCursorIDs(cursor.get(), {1, 4});
126 }
127
128 // remove less or equal to "Three"
129 {
130 std::unique_ptr<JSONDocument> query(
131 Parse("{'name': {'$lte': 'Three'}, '$index': 'name_index'}"));
132 ASSERT_OK(db_->Remove(ReadOptions(), WriteOptions(), *query));
133 }
134
135 // find all -- only "Two" left, everything else should be deleted
136 {
137 std::unique_ptr<JSONDocument> query(Parse("[]"));
138 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
139 AssertCursorIDs(cursor.get(), {2});
140 }
141}
142
143TEST_F(DocumentDBTest, ComplexQueryTest) {
144 DocumentDBOptions options;
145 DocumentDB::IndexDescriptor priority_index;
146 priority_index.description = Parse("{'priority': 1}");
147 priority_index.name = "priority";
148 DocumentDB::IndexDescriptor job_name_index;
149 job_name_index.description = Parse("{'job_name': 1}");
150 job_name_index.name = "job_name";
151 DocumentDB::IndexDescriptor progress_index;
152 progress_index.description = Parse("{'progress': 1}");
153 progress_index.name = "progress";
154
155 ASSERT_OK(DocumentDB::Open(options, dbname_, {}, &db_));
156 CreateIndexes({priority_index, progress_index});
157 delete priority_index.description;
158 delete progress_index.description;
159
160 std::vector<std::string> json_objects = {
161 "{'_id': 1, 'job_name': 'play', 'priority': 10, 'progress': 14.2}",
162 "{'_id': 2, 'job_name': 'white', 'priority': 2, 'progress': 45.1}",
163 "{'_id': 3, 'job_name': 'straw', 'priority': 5, 'progress': 83.2}",
164 "{'_id': 4, 'job_name': 'temporary', 'priority': 3, 'progress': 14.9}",
165 "{'_id': 5, 'job_name': 'white', 'priority': 4, 'progress': 44.2}",
166 "{'_id': 6, 'job_name': 'tea', 'priority': 1, 'progress': 12.4}",
167 "{'_id': 7, 'job_name': 'delete', 'priority': 2, 'progress': 77.54}",
168 "{'_id': 8, 'job_name': 'rock', 'priority': 3, 'progress': 93.24}",
169 "{'_id': 9, 'job_name': 'steady', 'priority': 3, 'progress': 9.1}",
170 "{'_id': 10, 'job_name': 'white', 'priority': 1, 'progress': 61.4}",
171 "{'_id': 11, 'job_name': 'who', 'priority': 4, 'progress': 39.41}",
172 "{'_id': 12, 'job_name': 'who', 'priority': -1, 'progress': 39.42}",
173 "{'_id': 13, 'job_name': 'who', 'priority': -2, 'progress': 39.42}", };
174
175 // add index on the fly!
176 CreateIndexes({job_name_index});
177 delete job_name_index.description;
178
179 for (auto& json : json_objects) {
180 std::unique_ptr<JSONDocument> document(Parse(json));
181 ASSERT_TRUE(document != nullptr);
182 ASSERT_OK(db_->Insert(WriteOptions(), *document));
183 }
184
185 // 2 < priority < 4 AND progress > 10.0, index priority
186 {
187 std::unique_ptr<JSONDocument> query(Parse(
188 "[{'$filter': {'priority': {'$lt': 4, '$gt': 2}, 'progress': {'$gt': "
189 "10.0}, '$index': 'priority'}}]"));
190 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
191 AssertCursorIDs(cursor.get(), {4, 8});
192 }
193
194 // -1 <= priority <= 1, index priority
195 {
196 std::unique_ptr<JSONDocument> query(Parse(
197 "[{'$filter': {'priority': {'$lte': 1, '$gte': -1},"
198 " '$index': 'priority'}}]"));
199 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
200 AssertCursorIDs(cursor.get(), {6, 10, 12});
201 }
202
203 // 2 < priority < 4 AND progress > 10.0, index progress
204 {
205 std::unique_ptr<JSONDocument> query(Parse(
206 "[{'$filter': {'priority': {'$lt': 4, '$gt': 2}, 'progress': {'$gt': "
207 "10.0}, '$index': 'progress'}}]"));
208 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
209 AssertCursorIDs(cursor.get(), {4, 8});
210 }
211
212 // job_name == 'white' AND priority >= 2, index job_name
213 {
214 std::unique_ptr<JSONDocument> query(Parse(
215 "[{'$filter': {'job_name': 'white', 'priority': {'$gte': "
216 "2}, '$index': 'job_name'}}]"));
217 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
218 AssertCursorIDs(cursor.get(), {2, 5});
219 }
220
221 // 35.0 <= progress < 65.5, index progress
222 {
223 std::unique_ptr<JSONDocument> query(Parse(
224 "[{'$filter': {'progress': {'$gt': 5.0, '$gte': 35.0, '$lt': 65.5}, "
225 "'$index': 'progress'}}]"));
226 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
227 AssertCursorIDs(cursor.get(), {2, 5, 10, 11, 12, 13});
228 }
229
230 // 2 < priority <= 4, index priority
231 {
232 std::unique_ptr<JSONDocument> query(Parse(
233 "[{'$filter': {'priority': {'$gt': 2, '$lt': 8, '$lte': 4}, "
234 "'$index': 'priority'}}]"));
235 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
236 AssertCursorIDs(cursor.get(), {4, 5, 8, 9, 11});
237 }
238
239 // Delete all whose progress is bigger than 50%
240 {
241 std::unique_ptr<JSONDocument> query(
242 Parse("{'progress': {'$gt': 50.0}, '$index': 'progress'}"));
243 ASSERT_OK(db_->Remove(ReadOptions(), WriteOptions(), *query));
244 }
245
246 // 2 < priority < 6, index priority
247 {
248 std::unique_ptr<JSONDocument> query(Parse(
249 "[{'$filter': {'priority': {'$gt': 2, '$lt': 6}, "
250 "'$index': 'priority'}}]"));
251 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
252 AssertCursorIDs(cursor.get(), {4, 5, 9, 11});
253 }
254
255 // update set priority to 10 where job_name is 'white'
256 {
257 std::unique_ptr<JSONDocument> query(Parse("{'job_name': 'white'}"));
258 std::unique_ptr<JSONDocument> update(Parse("{'$set': {'priority': 10}}"));
259 ASSERT_OK(db_->Update(ReadOptions(), WriteOptions(), *query, *update));
260 }
261
262 // update twice: set priority to 15 where job_name is 'white'
263 {
264 std::unique_ptr<JSONDocument> query(Parse("{'job_name': 'white'}"));
265 std::unique_ptr<JSONDocument> update(Parse("{'$set': {'priority': 10},"
266 "'$set': {'priority': 15}}"));
267 ASSERT_OK(db_->Update(ReadOptions(), WriteOptions(), *query, *update));
268 }
269
270 // update twice: set priority to 15 and
271 // progress to 40 where job_name is 'white'
272 {
273 std::unique_ptr<JSONDocument> query(Parse("{'job_name': 'white'}"));
274 std::unique_ptr<JSONDocument> update(
275 Parse("{'$set': {'priority': 10, 'progress': 35},"
276 "'$set': {'priority': 15, 'progress': 40}}"));
277 ASSERT_OK(db_->Update(ReadOptions(), WriteOptions(), *query, *update));
278 }
279
280 // priority < 0
281 {
282 std::unique_ptr<JSONDocument> query(
283 Parse("[{'$filter': {'priority': {'$lt': 0}, '$index': 'priority'}}]"));
284 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
285 ASSERT_OK(cursor->status());
286 AssertCursorIDs(cursor.get(), {12, 13});
287 }
288
289 // -2 < priority < 0
290 {
291 std::unique_ptr<JSONDocument> query(
292 Parse("[{'$filter': {'priority': {'$gt': -2, '$lt': 0},"
293 " '$index': 'priority'}}]"));
294 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
295 ASSERT_OK(cursor->status());
296 AssertCursorIDs(cursor.get(), {12});
297 }
298
299 // -2 <= priority < 0
300 {
301 std::unique_ptr<JSONDocument> query(
302 Parse("[{'$filter': {'priority': {'$gte': -2, '$lt': 0},"
303 " '$index': 'priority'}}]"));
304 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
305 ASSERT_OK(cursor->status());
306 AssertCursorIDs(cursor.get(), {12, 13});
307 }
308
309 // 4 < priority
310 {
311 std::unique_ptr<JSONDocument> query(
312 Parse("[{'$filter': {'priority': {'$gt': 4}, '$index': 'priority'}}]"));
313 std::unique_ptr<Cursor> cursor(db_->Query(ReadOptions(), *query));
314 ASSERT_OK(cursor->status());
315 AssertCursorIDs(cursor.get(), {1, 2, 5});
316 }
317
318 Status s = db_->DropIndex("doesnt-exist");
319 ASSERT_TRUE(!s.ok());
320 ASSERT_OK(db_->DropIndex("priority"));
321}
322
323} // namespace rocksdb
324
325int main(int argc, char** argv) {
326 ::testing::InitGoogleTest(&argc, argv);
327 return RUN_ALL_TESTS();
328}
329
330#else
331#include <stdio.h>
332
11fdf7f2 333int main(int /*argc*/, char** /*argv*/) {
7c673cae
FG
334 fprintf(stderr, "SKIPPED as DocumentDB is not supported in ROCKSDB_LITE\n");
335 return 0;
336}
337
338#endif // !ROCKSDB_LITE