• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / github_pull_request_278228

04 Oct 2023 10:15PM UTC coverage: 91.582% (+0.007%) from 91.575%
github_pull_request_278228

Pull #7029

Evergreen

tgoyne
Use UNITTEST_LOG_LEVEL in objectstore tests

For historical reasons core and sync tests use the UNITTEST_LOG_LEVEL
environment variable to determine the test log level, while object store tests
used a build time setting. This brings them into alignment on using the env
variable, and applies it via setting the default log level on startup in a
single place.
Pull Request #7029: Use UNITTEST_LOG_LEVEL in objectstore tests

94218 of 173442 branches covered (0.0%)

46 of 54 new or added lines in 5 files covered. (85.19%)

51 existing lines in 12 files now uncovered.

230351 of 251523 relevant lines covered (91.58%)

6704577.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.68
/test/fuzz_group.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 Realm 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
#include "fuzz_group.hpp"
20

21
#include <realm.hpp>
22
#include <realm/index_string.hpp>
23

24
#include <ctime>
25
#include <cstdio>
26
#include <fstream>
27
#include <iostream>
28

29
#include "util/test_path.hpp"
30

31
using namespace realm;
32
using namespace realm::util;
33

34
#define TEST_FUZZ
35
#ifdef TEST_FUZZ
36
// Determines whether or not to run the shared group verify function
37
// after each transaction. This will find errors earlier but is expensive.
38
#define REALM_VERIFY true
39

40
#if REALM_VERIFY
41
#define REALM_DO_IF_VERIFY(log, op)                                                                                  \
42
    do {                                                                                                             \
229✔
43
        if (log)                                                                                                     \
229✔
44
            *log << #op << ";\n";                                                                                    \
106✔
45
        op;                                                                                                          \
229✔
46
    } while (false)
229✔
47
#else
48
#define REALM_DO_IF_VERIFY(log, owner)                                                                               \
49
    do {                                                                                                             \
50
    } while (false)
51
#endif
52

53
namespace {
54

55
struct EndOfFile {
56
};
57

58
enum INS {
59
    ADD_TABLE,
60
    REMOVE_TABLE,
61
    CREATE_OBJECT,
62
    RENAME_COLUMN,
63
    ADD_COLUMN,
64
    REMOVE_COLUMN,
65
    SET,
66
    REMOVE_OBJECT,
67
    REMOVE_RECURSIVE,
68
    ADD_COLUMN_LINK,
69
    ADD_COLUMN_LINK_LIST,
70
    CLEAR_TABLE,
71
    ADD_SEARCH_INDEX,
72
    REMOVE_SEARCH_INDEX,
73
    COMMIT,
74
    ROLLBACK,
75
    ADVANCE,
76
    MOVE_LAST_OVER,
77
    CLOSE_AND_REOPEN,
78
    GET_ALL_COLUMN_NAMES,
79
    CREATE_TABLE_VIEW,
80
    COMPACT,
81
    IS_NULL,
82
    ENUMERATE_COLUMN,
83

84
    COUNT
85
};
86

87
DataType get_type(unsigned char c)
88
{
8✔
89
    DataType types[] = {type_Int, type_Bool, type_Float, type_Double, type_String, type_Binary, type_Timestamp};
8✔
90

5✔
91
    unsigned char mod = c % (sizeof(types) / sizeof(DataType));
8✔
92
    return types[mod];
8✔
93
}
8✔
94

95
struct State {
96
    std::string str;
97
    size_t pos;
98
};
99

100
unsigned char get_next(State& s)
101
{
1,206✔
102
    if (s.pos == s.str.size()) {
1,206✔
103
        throw EndOfFile{};
6✔
104
    }
6✔
105
    char byte = s.str[s.pos];
1,200✔
106
    s.pos++;
1,200✔
107
    return byte;
1,200✔
108
}
1,200✔
109

110
const char* get_encryption_key()
111
{
2✔
112
#if REALM_ENABLE_ENCRYPTION
2✔
113
    return "1234567890123456789012345678901123456789012345678901234567890123";
2✔
114
#else
115
    return nullptr;
116
#endif
117
}
2✔
118

119
int64_t get_int64(State& s)
120
{
×
121
    int64_t v = 0;
×
122
    for (size_t t = 0; t < 8; t++) {
×
123
        unsigned char c = get_next(s);
×
124
        *(reinterpret_cast<signed char*>(&v) + t) = c;
×
125
    }
×
126
    return v;
×
127
}
×
128

129
int32_t get_int32(State& s)
130
{
×
131
    int32_t v = 0;
×
132
    for (size_t t = 0; t < 4; t++) {
×
133
        unsigned char c = get_next(s);
×
134
        *(reinterpret_cast<signed char*>(&v) + t) = c;
×
135
    }
×
136
    return v;
×
137
}
×
138

139
std::string create_string(size_t length)
140
{
×
141
    REALM_ASSERT_3(length, <, 256);
×
142
    char buf[256] = {0};
×
143
    for (size_t i = 0; i < length; i++)
×
144
        buf[i] = 'a' + (rand() % 20);
×
145
    return std::string{buf, length};
×
146
}
×
147

148
std::pair<int64_t, int32_t> get_timestamp_values(State& s)
149
{
×
150
    int64_t seconds = get_int64(s);
×
151
    int32_t nanoseconds = get_int32(s) % 1000000000;
×
152
    // Make sure the values form a sensible Timestamp
153
    const bool both_non_negative = seconds >= 0 && nanoseconds >= 0;
×
154
    const bool both_non_positive = seconds <= 0 && nanoseconds <= 0;
×
155
    const bool correct_timestamp = both_non_negative || both_non_positive;
×
156
    if (!correct_timestamp) {
×
157
        nanoseconds = -nanoseconds;
×
158
    }
×
159
    return {seconds, nanoseconds};
×
160
}
×
161

162
int table_index = 0;
163
int column_index = 0;
164

165
std::string create_column_name(DataType t)
166
{
32✔
167
    std::string str;
32✔
168
    switch (t) {
32✔
169
        case type_Int:
2✔
170
            str = "int_";
2✔
171
            break;
2✔
172
        case type_Bool:
2✔
173
            str = "bool_";
2✔
174
            break;
2✔
175
        case type_Float:
1✔
176
            str = "float_";
1✔
177
            break;
1✔
178
        case type_Double:
1✔
179
            str = "double_";
1✔
180
            break;
1✔
181
        case type_String:
3✔
182
            str = "string_";
3✔
183
            break;
3✔
184
        case type_Binary:
1✔
185
            str = "binary_";
1✔
186
            break;
1✔
UNCOV
187
        case type_Timestamp:
✔
UNCOV
188
            str = "date_";
×
UNCOV
189
            break;
×
190
        case type_Decimal:
✔
191
            str = "decimal_";
×
192
            break;
×
193
        case type_ObjectId:
✔
194
            str = "id_";
×
195
            break;
×
196
        case type_Link:
17✔
197
            str = "link_";
17✔
198
            break;
17✔
199
        case type_TypedLink:
✔
200
            str = "typed_link_";
×
201
            break;
×
202
        case type_LinkList:
5✔
203
            str = "link_list_";
5✔
204
            break;
5✔
205
        case type_UUID:
✔
206
            str = "uuid_";
×
207
            break;
×
208
        case type_Mixed:
✔
209
            str = "any_";
×
210
            break;
×
211
    }
32✔
212
    return str + util::to_string(column_index++);
32✔
213
}
32✔
214

215
std::string create_table_name()
216
{
29✔
217
    std::string str = "Table_";
29✔
218
    return str + util::to_string(table_index++);
29✔
219
}
29✔
220

221
std::string get_current_time_stamp()
222
{
×
223
    std::time_t t = std::time(nullptr);
×
224
    const int str_size = 100;
×
225
    char str_buffer[str_size] = {0};
×
226
    std::strftime(str_buffer, str_size, "%c", std::localtime(&t));
×
227
    return str_buffer;
×
228
}
×
229

230
// You can use this variable to make a conditional breakpoint if you know that
231
// a problem occurs after a certain amount of iterations.
232
int iteration = 0;
233
} // anonymous namespace
234

235
void parse_and_apply_instructions(std::string& in, const std::string& path, std::ostream* log)
236
{
6✔
237
    const size_t add_empty_row_max = REALM_MAX_BPNODE_SIZE * REALM_MAX_BPNODE_SIZE + 1000;
6✔
238
    const size_t max_tables = REALM_MAX_BPNODE_SIZE * 10;
6✔
239

3✔
240
    // Max number of rows in a table. Overridden only by create_object() and only in the case where
3✔
241
    // max_rows is not exceeded *prior* to executing add_empty_row.
3✔
242
    const size_t max_rows = 100000;
6✔
243
    column_index = table_index = 0;
6✔
244

3✔
245
    State s;
6✔
246
    s.str = in;
6✔
247
    s.pos = 0;
6✔
248

3✔
249
    // const bool use_encryption = false;
3✔
250
    const bool use_encryption = get_next(s) % 2 == 0;
6✔
251
    const char* encryption_key = use_encryption ? get_encryption_key() : nullptr;
5✔
252

3✔
253
    if (log) {
6✔
254
        *log << "// Test case generated in " REALM_VER_CHUNK " on " << get_current_time_stamp() << ".\n";
×
255
        *log << "// REALM_MAX_BPNODE_SIZE is " << REALM_MAX_BPNODE_SIZE << "\n";
×
256
        *log << "// ----------------------------------------------------------------------\n";
×
257
        std::string printable_key;
×
258
        if (encryption_key == nullptr) {
×
259
            printable_key = "nullptr";
×
260
        }
×
261
        else {
×
262
            printable_key = std::string("\"") + encryption_key + "\"";
×
263
        }
×
264

265
        *log << "SHARED_GROUP_TEST_PATH(path);\n";
×
266

267
        *log << "const char* key = " << printable_key << ";\n";
×
268
        *log << "std::unique_ptr<Replication> hist(make_in_realm_history());\n";
×
269

270
        *log << "DBRef db = DB::create(*hist, path, DBOptions(key));\n";
×
271
        *log << "auto wt = db->start_write();\n";
×
272
        *log << "auto rt = db->start_read();\n";
×
273
        *log << "std::vector<TableView> table_views;\n";
×
274

275
        *log << "\n";
×
276
    }
×
277

3✔
278
    std::unique_ptr<Replication> hist(make_in_realm_history());
6✔
279

3✔
280
    DBOptions options(encryption_key);
6✔
281
    DBRef db = DB::create(*hist, path, options);
6✔
282
    auto wt = db->start_write();
6✔
283
    auto rt = db->start_read();
6✔
284
    std::vector<TableView> table_views;
6✔
285

3✔
286
    try {
6✔
287

3✔
288
        for (;;) {
939✔
289
            char instr = get_next(s) % COUNT;
939✔
290
            iteration++;
939✔
291

429✔
292
            /* This can help when debugging
429✔
293
            if (log) {
429✔
294
                *log << iteration << " ";
429✔
295
            }
429✔
296
            */
429✔
297

429✔
298
            if (instr == ADD_TABLE && wt->size() < max_tables) {
939✔
299
                std::string name = create_table_name();
29✔
300
                if (log) {
29✔
301
                    *log << "wt->add_table(\"" << name << "\");\n";
×
302
                }
×
303
                wt->add_table(name);
29✔
304
            }
29✔
305
            else if (instr == REMOVE_TABLE && wt->size() > 0) {
910✔
306
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
13✔
307
                if (log) {
13✔
308
                    *log << "try { wt->remove_table(" << table_key
×
309
                         << "); }"
×
310
                            " catch (const CrossTableLinkTarget&) { }\n";
×
311
                }
×
312
                try {
13✔
313
                    wt->remove_table(table_key);
13✔
314
                }
13✔
315
                catch (const CrossTableLinkTarget&) {
5✔
316
                    if (log) {
×
317
                        *log << "// Exception\n";
×
318
                    }
×
319
                }
×
320
            }
13✔
321
            else if (instr == CLEAR_TABLE && wt->size() > 0) {
897✔
322
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
12✔
323
                if (log) {
12✔
324
                    *log << "wt->get_table(" << table_key << ")->clear();\n";
×
325
                }
×
326
                wt->get_table(table_key)->clear();
12✔
327
            }
12✔
328
            else if (instr == CREATE_OBJECT && wt->size() > 0) {
885✔
329
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
10✔
330
                size_t num_rows = get_next(s);
10✔
331
                if (wt->get_table(table_key)->size() + num_rows < max_rows) {
10✔
332
                    if (log) {
10✔
333
                        *log << "{ std::vector<ObjKey> keys; wt->get_table(" << table_key << ")->create_objects("
×
334
                             << num_rows % add_empty_row_max << ", keys); }\n";
×
335
                    }
×
336
                    std::vector<ObjKey> keys;
10✔
337
                    wt->get_table(table_key)->create_objects(num_rows % add_empty_row_max, keys);
10✔
338
                }
10✔
339
            }
10✔
340
            else if (instr == ADD_COLUMN && wt->size() > 0) {
875✔
341
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
9✔
342
                DataType type = get_type(get_next(s));
9✔
343
                std::string name = create_column_name(type);
9✔
344
                // Mixed cannot be nullable. For other types, chose nullability randomly
5✔
345
                bool nullable = (get_next(s) % 2 == 0);
9✔
346
                if (log) {
9✔
347
                    *log << "wt->get_table(" << table_key << ")->add_column(DataType(" << int(type) << "), \"" << name
×
348
                         << "\", " << (nullable ? "true" : "false") << ");";
×
349
                }
×
350
                auto col = wt->get_table(table_key)->add_column(type, name, nullable);
9✔
351
                if (log) {
9✔
352
                    *log << " // -> " << col << "\n";
×
353
                }
×
354
            }
9✔
355
            else if (instr == REMOVE_COLUMN && wt->size() > 0) {
866✔
356
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
17✔
357
                TableRef t = wt->get_table(table_key);
17✔
358
                auto column_keys = t->get_column_keys();
17✔
359
                if (!column_keys.empty()) {
17✔
360
                    ColKey col = column_keys[get_next(s) % column_keys.size()];
3✔
361
                    if (log) {
3✔
362
                        *log << "wt->get_table(" << table_key << ")->remove_column(" << col << ");\n";
×
363
                    }
×
364
                    t->remove_column(col);
3✔
365
                }
3✔
366
            }
17✔
367
            else if (instr == RENAME_COLUMN && wt->size() > 0) {
849✔
368
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
13✔
369
                TableRef t = wt->get_table(table_key);
13✔
370
                auto column_keys = t->get_column_keys();
13✔
371
                if (!column_keys.empty()) {
13✔
372
                    ColKey col = column_keys[get_next(s) % column_keys.size()];
8✔
373
                    std::string name = create_column_name(t->get_column_type(col));
8✔
374
                    if (log) {
8✔
375
                        *log << "wt->get_table(" << table_key << ")->rename_column(" << col << ", \"" << name
×
376
                             << "\");\n";
×
377
                    }
×
378
                    t->rename_column(col, name);
8✔
379
                }
8✔
380
            }
13✔
381
            else if (instr == ADD_SEARCH_INDEX && wt->size() > 0) {
836✔
382
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
14✔
383
                TableRef t = wt->get_table(table_key);
14✔
384
                auto column_keys = t->get_column_keys();
14✔
385
                if (!column_keys.empty()) {
14✔
386
                    ColKey col = column_keys[get_next(s) % column_keys.size()];
2✔
387
                    bool supports_search_index = StringIndex::type_supported(t->get_column_type(col));
2✔
388

1✔
389
                    if (supports_search_index) {
2✔
390
                        if (log) {
2✔
391
                            *log << "wt->get_table(" << table_key << ")->add_search_index(" << col << ");\n";
×
392
                        }
×
393
                        t->add_search_index(col);
2✔
394
                    }
2✔
395
                }
2✔
396
            }
14✔
397
            else if (instr == REMOVE_SEARCH_INDEX && wt->size() > 0) {
822✔
398
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
17✔
399
                TableRef t = wt->get_table(table_key);
17✔
400
                auto column_keys = t->get_column_keys();
17✔
401
                if (!column_keys.empty()) {
17✔
402
                    ColKey col = column_keys[get_next(s) % column_keys.size()];
3✔
403
                    // We don't need to check if the column is of a type that is indexable or if it has index on or
3✔
404
                    // off
3✔
405
                    // because Realm will just do a no-op at worst (no exception or assert).
3✔
406
                    if (log) {
3!
407
                        *log << "wt->get_table(" << table_key << ")->remove_search_index(" << col << ");\n";
×
408
                    }
×
409
                    t->remove_search_index(col);
3✔
410
                }
3✔
411
            }
17✔
412
            else if (instr == ADD_COLUMN_LINK && wt->size() >= 1) {
805✔
413
                TableKey table_key_1 = wt->get_table_keys()[get_next(s) % wt->size()];
12✔
414
                TableKey table_key_2 = wt->get_table_keys()[get_next(s) % wt->size()];
12✔
415
                TableRef t1 = wt->get_table(table_key_1);
12✔
416
                TableRef t2 = wt->get_table(table_key_2);
12✔
417
                std::string name = create_column_name(type_Link);
12✔
418
                if (log) {
12✔
419
                    *log << "wt->get_table(" << table_key_1 << ")->add_column_link(type_Link, \"" << name
×
420
                         << "\", *wt->get_table(" << table_key_2 << "));";
×
421
                }
×
422
                auto col = t1->add_column(*t2, name);
12✔
423
                if (log) {
12✔
424
                    *log << " // -> " << col << "\n";
×
425
                }
×
426
            }
12✔
427
            else if (instr == ADD_COLUMN_LINK_LIST && wt->size() >= 2) {
793✔
428
                TableKey table_key_1 = wt->get_table_keys()[get_next(s) % wt->size()];
5✔
429
                TableKey table_key_2 = wt->get_table_keys()[get_next(s) % wt->size()];
5✔
430
                TableRef t1 = wt->get_table(table_key_1);
5✔
431
                TableRef t2 = wt->get_table(table_key_2);
5✔
432
                std::string name = create_column_name(type_LinkList);
5✔
433
                if (log) {
5✔
434
                    *log << "wt->get_table(" << table_key_1 << ")->add_column_link(type_LinkList, \"" << name
×
435
                         << "\", *wt->get_table(" << table_key_2 << "));";
×
436
                }
×
437
                auto col = t1->add_column_list(*t2, name);
5✔
438
                if (log) {
5✔
439
                    *log << " // -> " << col << "\n";
×
440
                }
×
441
            }
5✔
442
            else if (instr == SET && wt->size() > 0) {
788✔
443
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
19✔
444
                TableRef t = wt->get_table(table_key);
19✔
445
                auto all_col_keys = t->get_column_keys();
19✔
446
                if (!all_col_keys.empty() && t->size() > 0) {
19!
447
                    ColKey col = all_col_keys[get_next(s) % all_col_keys.size()];
×
448
                    size_t row = get_next(s) % t->size();
×
449
                    DataType type = t->get_column_type(col);
×
450
                    Obj obj = t->get_object(row);
×
451
                    if (log) {
×
452
                        *log << "{\nObj obj = wt->get_table(" << table_key << ")->get_object(" << row << ");\n";
×
453
                    }
×
454

455
                    // With equal probability, either set to null or to a value
456
                    if (get_next(s) % 2 == 0 && t->is_nullable(col)) {
×
457
                        if (type == type_Link) {
×
458
                            if (log) {
×
459
                                *log << "obj.set(" << col << ", null_key);\n";
×
460
                            }
×
461
                            obj.set(col, null_key);
×
462
                        }
×
463
                        else {
×
464
                            if (log) {
×
465
                                *log << "obj.set_null(" << col << ");\n";
×
466
                            }
×
467
                            obj.set_null(col);
×
468
                        }
×
469
                    }
×
470
                    else {
×
471
                        if (type == type_String) {
×
472
                            std::string str = create_string(get_next(s));
×
473
                            if (log) {
×
474
                                *log << "obj.set(" << col << ", \"" << str << "\");\n";
×
475
                            }
×
476
                            obj.set(col, StringData(str));
×
477
                        }
×
478
                        else if (type == type_Binary) {
×
479
                            std::string str = create_string(get_next(s));
×
480
                            if (log) {
×
481
                                *log << "obj.set<Binary>(" << col << ", BinaryData{\"" << str << "\", " << str.size()
×
482
                                     << "});\n";
×
483
                            }
×
484
                            obj.set<Binary>(col, BinaryData(str));
×
485
                        }
×
486
                        else if (type == type_Int) {
×
487
                            bool add_int = get_next(s) % 2 == 0;
×
488
                            int64_t value = get_int64(s);
×
489
                            if (add_int) {
×
490
                                if (log) {
×
491
                                    *log << "try { obj.add_int(" << col << ", " << value
×
492
                                         << "); } catch (const LogicError& le) { CHECK(le.kind() == "
×
493
                                            "LogicError::illegal_combination); }\n";
×
494
                                }
×
495
                                try {
×
496
                                    obj.add_int(col, value);
×
497
                                }
×
498
                                catch (const LogicError& le) {
×
499
                                    if (le.code() != ErrorCodes::IllegalOperation) {
×
500
                                        throw;
×
501
                                    }
×
502
                                }
×
503
                            }
×
504
                            else {
×
505
                                if (log) {
×
506
                                    *log << "obj.set<Int>(" << col << ", " << value << ");\n";
×
507
                                }
×
508
                                obj.set<Int>(col, value);
×
509
                            }
×
510
                        }
×
511
                        else if (type == type_Bool) {
×
512
                            bool value = get_next(s) % 2 == 0;
×
513
                            if (log) {
×
514
                                *log << "obj.set<Bool>(" << col << ", " << (value ? "true" : "false") << ");\n";
×
515
                            }
×
516
                            obj.set<Bool>(col, value);
×
517
                        }
×
518
                        else if (type == type_Float) {
×
519
                            float value = get_next(s);
×
520
                            if (log) {
×
521
                                *log << "obj.set<Float>(" << col << ", " << value << ");\n";
×
522
                            }
×
523
                            obj.set<Float>(col, value);
×
524
                        }
×
525
                        else if (type == type_Double) {
×
526
                            double value = get_next(s);
×
527
                            if (log) {
×
528
                                *log << "obj.set<double>(" << col << ", " << value << ");\n";
×
529
                            }
×
530
                            obj.set<double>(col, value);
×
531
                        }
×
532
                        else if (type == type_Link) {
×
533
                            TableRef target = t->get_link_target(col);
×
534
                            if (target->size() > 0) {
×
535
                                ObjKey target_key = target->get_object(get_next(s) % target->size()).get_key();
×
536
                                if (log) {
×
537
                                    *log << "obj.set<Key>(" << col << ", " << target_key << ");\n";
×
538
                                }
×
539
                                obj.set(col, target_key);
×
540
                            }
×
541
                        }
×
542
                        else if (type == type_LinkList) {
×
543
                            TableRef target = t->get_link_target(col);
×
544
                            if (target->size() > 0) {
×
545
                                LnkLst links = obj.get_linklist(col);
×
546
                                ObjKey target_key = target->get_object(get_next(s) % target->size()).get_key();
×
547
                                // either add or set, 50/50 probability
548
                                if (links.size() > 0 && get_next(s) > 128) {
×
549
                                    size_t linklist_row = get_next(s) % links.size();
×
550
                                    if (log) {
×
551
                                        *log << "obj.get_linklist(" << col << ")->set(" << linklist_row << ", "
×
552
                                             << target_key << ");\n";
×
553
                                    }
×
554
                                    links.set(linklist_row, target_key);
×
555
                                }
×
556
                                else {
×
557
                                    if (log) {
×
558
                                        *log << "obj.get_linklist(" << col << ")->add(" << target_key << ");\n";
×
559
                                    }
×
560
                                    links.add(target_key);
×
561
                                }
×
562
                            }
×
563
                        }
×
564
                        else if (type == type_Timestamp) {
×
565
                            std::pair<int64_t, int32_t> values = get_timestamp_values(s);
×
566
                            Timestamp value{values.first, values.second};
×
567
                            if (log) {
×
568
                                *log << "obj.set(" << col << ", " << value << ");\n";
×
569
                            }
×
570
                            obj.set(col, value);
×
571
                        }
×
572
                    }
×
573
                    if (log) {
×
574
                        *log << "}\n";
×
575
                    }
×
576
                }
×
577
            }
19✔
578
            else if (instr == REMOVE_OBJECT && wt->size() > 0) {
769✔
579
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
12✔
580
                TableRef t = wt->get_table(table_key);
12✔
581
                if (t->size() > 0) {
12✔
582
                    ObjKey key = t->get_object(get_next(s) % t->size()).get_key();
×
583
                    if (log) {
×
584
                        *log << "wt->get_table(" << table_key << ")->remove_object(" << key << ");\n";
×
585
                    }
×
586
                    t->remove_object(key);
×
587
                }
×
588
            }
12✔
589
            else if (instr == REMOVE_RECURSIVE && wt->size() > 0) {
757✔
590
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
15✔
591
                TableRef t = wt->get_table(table_key);
15✔
592
                if (t->size() > 0) {
15✔
593
                    ObjKey key = t->get_object(get_next(s) % t->size()).get_key();
3✔
594
                    if (log) {
3!
595
                        *log << "wt->get_table(" << table_key << ")->remove_object_recursive(" << key << ");\n";
×
596
                    }
×
597
                    t->remove_object_recursive(key);
3✔
598
                }
3✔
599
            }
15✔
600
            else if (instr == ENUMERATE_COLUMN && wt->size() > 0) {
742✔
601
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
12✔
602
                TableRef t = wt->get_table(table_key);
12✔
603
                auto all_col_keys = t->get_column_keys();
12✔
604
                if (!all_col_keys.empty()) {
12✔
605
                    size_t ndx = get_next(s) % all_col_keys.size();
4✔
606
                    ColKey col = all_col_keys[ndx];
4✔
607
                    if (log) {
4!
608
                        *log << "wt->get_table(" << table_key << ")->enumerate_string_column(" << col << ");\n";
×
609
                    }
×
610
                    wt->get_table(table_key)->enumerate_string_column(col);
4✔
611
                }
4✔
612
            }
12✔
613
            else if (instr == COMMIT) {
730✔
614
                if (log) {
46✔
615
                    *log << "wt->commit_and_continue_as_read();\n";
×
616
                }
×
617
                wt->commit_and_continue_as_read();
46✔
618
                REALM_DO_IF_VERIFY(log, wt->verify());
46✔
619
                if (log) {
46✔
620
                    *log << "wt->promote_to_write();\n";
×
621
                }
×
622
                wt->promote_to_write();
46✔
623
                REALM_DO_IF_VERIFY(log, wt->verify());
46✔
624
            }
46✔
625
            else if (instr == ROLLBACK) {
684✔
626
                if (log) {
34✔
627
                    *log << "wt->rollback_and_continue_as_read();\n";
×
628
                }
×
629
                wt->rollback_and_continue_as_read();
34✔
630
                REALM_DO_IF_VERIFY(log, wt->verify());
34✔
631
                if (log) {
34✔
632
                    *log << "wt->promote_to_write();\n";
×
633
                }
×
634
                wt->promote_to_write();
34✔
635
                REALM_DO_IF_VERIFY(log, wt->verify());
34✔
636
            }
34✔
637
            else if (instr == ADVANCE) {
650✔
638
                if (log) {
34✔
639
                    *log << "rt->advance_read();\n";
×
640
                }
×
641
                rt->advance_read();
34✔
642
                REALM_DO_IF_VERIFY(log, rt->verify());
34✔
643
            }
34✔
644
            else if (instr == CLOSE_AND_REOPEN) {
616✔
645
                if (log) {
35✔
646
                    *log << "wt = nullptr;\n";
×
647
                    *log << "rt = nullptr;\n";
×
648
                    *log << "db->close();\n";
×
649
                }
×
650
                wt = nullptr; // transactions must be done/closed before closing the DB.
35✔
651
                rt = nullptr;
35✔
652
                db->close();
35✔
653
                if (log) {
35✔
654
                    *log << "db = DB::create(*hist, path, DBOptions(key));\n";
×
655
                }
×
656
                db = DB::create(*hist, path, DBOptions(encryption_key));
35✔
657
                if (log) {
35✔
658
                    *log << "wt = db_w->start_write();\n";
×
659
                    *log << "rt = db->start_read();\n";
×
660
                }
×
661
                rt = db->start_read();
35✔
662
                wt = db->start_write();
35✔
663
                REALM_DO_IF_VERIFY(log, rt->verify());
35✔
664
            }
35✔
665
            else if (instr == GET_ALL_COLUMN_NAMES && wt->size() > 0) {
581✔
666
                // try to fuzz find this: https://github.com/realm/realm-core/issues/1769
7✔
667
                for (auto table_key : wt->get_table_keys()) {
23✔
668
                    TableRef t = wt->get_table(table_key);
23✔
669
                    auto all_col_keys = t->get_column_keys();
23✔
670
                    for (auto col : all_col_keys) {
11✔
671
                        StringData col_name = t->get_column_name(col);
9✔
672
                        static_cast<void>(col_name);
9✔
673
                    }
9✔
674
                }
23✔
675
            }
19✔
676
            else if (instr == CREATE_TABLE_VIEW && wt->size() > 0) {
562✔
677
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
11✔
678
                TableRef t = wt->get_table(table_key);
11✔
679
                if (log) {
11✔
680
                    *log << "table_views.push_back(wt->get_table(" << table_key << ")->where().find_all());\n";
×
681
                }
×
682
                TableView tv = t->where().find_all();
11✔
683
                table_views.push_back(tv);
11✔
684
            }
11✔
685
            else if (instr == COMPACT) {
551✔
686
                /*
17✔
687
                if (log) {
17✔
688
                    *log << "db_r.close();\n";
17✔
689
                }
17✔
690
                db_r.close();
17✔
691
                if (log) {
17✔
692
                    *log << "wt->commit();\n";
17✔
693
                }
17✔
694
                wt->commit();
17✔
695

17✔
696
                if (log) {
17✔
697
                    *log << "REALM_ASSERT_RELEASE(db_w.compact());\n";
17✔
698
                }
17✔
699
                REALM_ASSERT_RELEASE(db_w.compact());
17✔
700

17✔
701
                if (log) {
17✔
702
                    *log << "wt = db_w.start_write();\n";
17✔
703
                }
17✔
704
                wt = db_w.start_write();
17✔
705
                if (log) {
17✔
706
                    *log << "db_r.open(path, true, DBOptions(key));\n";
17✔
707
                }
17✔
708
                db_r.open(path, true, DBOptions(encryption_key));
17✔
709
                if (log) {
17✔
710
                    *log << "rt = db_r.start_read();\n";
17✔
711
                }
17✔
712
                rt = db_r.start_read();
17✔
713
                REALM_DO_IF_VERIFY(log, rt->verify());
17✔
714
                */
17✔
715
            }
29✔
716
            else if (instr == IS_NULL && rt->size() > 0) {
522✔
717
                TableKey table_key = rt->get_table_keys()[get_next(s) % rt->size()];
3✔
718
                TableRef t = rt->get_table(table_key);
3✔
719
                if (t->get_column_count() > 0 && t->size() > 0) {
3!
720
                    auto all_col_keys = t->get_column_keys();
1✔
721
                    size_t ndx = get_next(s) % all_col_keys.size();
1✔
722
                    ColKey col = all_col_keys[ndx];
1✔
723
                    ObjKey key = t->get_object(get_int32(s) % t->size()).get_key();
1✔
724
                    if (log) {
1!
725
                        *log << "wt->get_table(" << table_key << ")->get_object(" << key << ").is_null(" << col
×
726
                             << ");\n";
×
727
                    }
×
728
                    bool res = t->get_object(key).is_null(col);
1✔
729
                    static_cast<void>(res);
1✔
730
                }
1✔
731
            }
3✔
732
        }
939✔
733
    }
6✔
734
    catch (const EndOfFile&) {
6✔
735
    }
6✔
736
}
6✔
737

738

739
static void usage(const char* argv[])
740
{
×
741
    fprintf(stderr,
×
742
            "Usage: %s {FILE | --} [--log] [--name NAME] [--prefix PATH]\n"
×
743
            "Where FILE is a instruction file that will be replayed.\n"
×
744
            "Pass -- without argument to read filenames from stdin\n"
×
745
            "Pass --log to have code printed to stdout producing the same instructions.\n"
×
746
            "Pass --name NAME with distinct values when running on multiple threads,\n"
×
747
            "                 to make sure the test don't use the same Realm file\n"
×
748
            "Pass --prefix PATH to supply a path that should be prepended to all filenames\n"
×
749
            "                 read from stdin.\n",
×
750
            argv[0]);
×
751
    exit(1);
×
752
}
×
753

754
int run_fuzzy(int argc, const char* argv[])
755
{
×
756
    std::ostream* log = nullptr;
×
757
    std::string name = "fuzz-test";
×
758
    std::string prefix = "./";
×
759
    bool file_names_from_stdin = false;
×
760

761
    size_t file_arg = size_t(-1);
×
762
    for (size_t i = 1; i < size_t(argc); ++i) {
×
763
        std::string arg = argv[i];
×
764
        if (arg == "--log") {
×
765
            log = &std::cout;
×
766
        }
×
767
        else if (arg == "--") {
×
768
            file_names_from_stdin = true;
×
769
        }
×
770
        else if (arg == "--prefix") {
×
771
            prefix = argv[++i];
×
772
        }
×
773
        else if (arg == "--name") {
×
774
            name = argv[++i];
×
775
        }
×
776
        else {
×
777
            file_arg = i;
×
778
        }
×
779
    }
×
780

781
    if (!file_names_from_stdin && file_arg == size_t(-1)) {
×
782
        usage(argv);
×
783
    }
×
784

785
    disable_sync_to_disk();
×
786

787
    if (file_names_from_stdin) {
×
788
        std::string file_name;
×
789

790
        std::cin >> file_name;
×
791
        while (std::cin) {
×
792
            std::ifstream in(prefix + file_name, std::ios::in | std::ios::binary);
×
793
            if (!in.is_open()) {
×
794
                std::cerr << "Could not open file for reading: " << (prefix + file_name) << std::endl;
×
795
            }
×
796
            else {
×
797
                std::cout << file_name << std::endl;
×
798
                realm::test_util::RealmPathInfo test_context{name};
×
799
                SHARED_GROUP_TEST_PATH(path);
×
800

801
                std::string contents((std::istreambuf_iterator<char>(in)), (std::istreambuf_iterator<char>()));
×
802
                parse_and_apply_instructions(contents, path, log);
×
803
            }
×
804

805
            std::cin >> file_name;
×
806
        }
×
807
    }
×
808
    else {
×
809
        std::ifstream in(argv[file_arg], std::ios::in | std::ios::binary);
×
810
        if (!in.is_open()) {
×
811
            std::cerr << "Could not open file for reading: " << argv[file_arg] << "\n";
×
812
            exit(1);
×
813
        }
×
814

815
        realm::test_util::RealmPathInfo test_context{name};
×
816
        SHARED_GROUP_TEST_PATH(path);
×
817

818
        std::string contents((std::istreambuf_iterator<char>(in)), (std::istreambuf_iterator<char>()));
×
819
        parse_and_apply_instructions(contents, path, log);
×
820
    }
×
821

822
    return 0;
×
823
}
×
824
#else
825
int run_fuzzy(int, const char*[])
826
{
827
    return 0;
828
}
829
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc