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

realm / realm-core / james.stone_543

10 May 2024 08:59PM UTC coverage: 90.808% (-0.03%) from 90.837%
james.stone_543

Pull #7689

Evergreen

ironage
fix a test on windows
Pull Request #7689: RNET-1141 multiprocess encryption for writers with different page sizes

102068 of 181122 branches covered (56.35%)

202 of 223 new or added lines in 3 files covered. (90.58%)

119 existing lines in 13 files now uncovered.

214742 of 236479 relevant lines covered (90.81%)

5817458.76 hits per line

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

43.22
/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 {                                                                                                             \
218✔
43
        if (log)                                                                                                     \
218✔
44
            *log << #op << ";\n";                                                                                    \
218✔
45
        op;                                                                                                          \
218✔
46
    } while (false)
218✔
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
enum INS {
58
    ADD_TABLE,
59
    REMOVE_TABLE,
60
    CREATE_OBJECT,
61
    RENAME_COLUMN,
62
    ADD_COLUMN,
63
    REMOVE_COLUMN,
64
    SET,
65
    REMOVE_OBJECT,
66
    REMOVE_RECURSIVE,
67
    ADD_COLUMN_LINK,
68
    ADD_COLUMN_LINK_LIST,
69
    CLEAR_TABLE,
70
    ADD_SEARCH_INDEX,
71
    REMOVE_SEARCH_INDEX,
72
    COMMIT,
73
    ROLLBACK,
74
    ADVANCE,
75
    MOVE_LAST_OVER,
76
    CLOSE_AND_REOPEN,
77
    GET_ALL_COLUMN_NAMES,
78
    CREATE_TABLE_VIEW,
79
    COMPACT,
80
    IS_NULL,
81
    ENUMERATE_COLUMN,
82

83
    COUNT
84
};
85

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

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

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

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

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

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

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

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

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

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

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

211
std::string create_table_name()
212
{
37✔
213
    std::string str = "Table_";
37✔
214
    return str + util::to_string(table_index++);
37✔
215
}
37✔
216

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

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

231
void parse_and_apply_instructions(std::string& in, const std::string& path, std::ostream* log)
232
{
6✔
233
    const size_t add_empty_row_max = REALM_MAX_BPNODE_SIZE * REALM_MAX_BPNODE_SIZE + 1000;
6✔
234
    const size_t max_tables = REALM_MAX_BPNODE_SIZE * 10;
6✔
235

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

241
    State s;
6✔
242
    s.str = in;
6✔
243
    s.pos = 0;
6✔
244

245
    // const bool use_encryption = false;
246
    const bool use_encryption = get_next(s) % 2 == 0;
6✔
247
    const char* encryption_key = use_encryption ? get_encryption_key() : nullptr;
6✔
248

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

261
        *log << "SHARED_GROUP_TEST_PATH(path);\n";
×
262

263
        *log << "const char* key = " << printable_key << ";\n";
×
264
        *log << "std::unique_ptr<Replication> hist(make_in_realm_history());\n";
×
265

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

271
        *log << "\n";
×
272
    }
×
273

274
    std::unique_ptr<Replication> hist(make_in_realm_history());
6✔
275

276
    DBOptions options(encryption_key);
6✔
277
    DBRef db = DB::create(*hist, path, options);
6✔
278
    auto wt = db->start_write();
6✔
279
    auto rt = db->start_read();
6✔
280
    std::vector<TableView> table_views;
6✔
281

282
    try {
6✔
283

284
        for (;;) {
939✔
285
            char instr = get_next(s) % COUNT;
939✔
286
            iteration++;
939✔
287

288
            /* This can help when debugging
289
            if (log) {
290
                *log << iteration << " ";
291
            }
292
            */
293

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

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

451
                    // With equal probability, either set to null or to a value
UNCOV
452
                    if (get_next(s) % 2 == 0 && t->is_nullable(col)) {
×
UNCOV
453
                        if (type == type_Link) {
×
UNCOV
454
                            if (log) {
×
455
                                *log << "obj.set(" << col << ", null_key);\n";
×
456
                            }
×
UNCOV
457
                            obj.set(col, null_key);
×
UNCOV
458
                        }
×
459
                        else {
×
460
                            if (log) {
×
461
                                *log << "obj.set_null(" << col << ");\n";
×
462
                            }
×
463
                            obj.set_null(col);
×
464
                        }
×
UNCOV
465
                    }
×
UNCOV
466
                    else {
×
UNCOV
467
                        if (type == type_String) {
×
468
                            std::string str = create_string(get_next(s));
×
469
                            if (log) {
×
470
                                *log << "obj.set(" << col << ", \"" << str << "\");\n";
×
471
                            }
×
472
                            obj.set(col, StringData(str));
×
473
                        }
×
UNCOV
474
                        else if (type == type_Binary) {
×
475
                            std::string str = create_string(get_next(s));
×
476
                            if (log) {
×
477
                                *log << "obj.set<Binary>(" << col << ", BinaryData{\"" << str << "\", " << str.size()
×
478
                                     << "});\n";
×
479
                            }
×
480
                            obj.set<Binary>(col, BinaryData(str));
×
481
                        }
×
UNCOV
482
                        else if (type == type_Int) {
×
483
                            bool add_int = get_next(s) % 2 == 0;
×
484
                            int64_t value = get_int64(s);
×
485
                            if (add_int) {
×
486
                                if (log) {
×
487
                                    *log << "try { obj.add_int(" << col << ", " << value
×
488
                                         << "); } catch (const LogicError& le) { CHECK(le.kind() == "
×
489
                                            "LogicError::illegal_combination); }\n";
×
490
                                }
×
491
                                try {
×
492
                                    obj.add_int(col, value);
×
493
                                }
×
494
                                catch (const LogicError& le) {
×
495
                                    if (le.code() != ErrorCodes::IllegalOperation) {
×
496
                                        throw;
×
497
                                    }
×
498
                                }
×
499
                            }
×
500
                            else {
×
501
                                if (log) {
×
502
                                    *log << "obj.set<Int>(" << col << ", " << value << ");\n";
×
503
                                }
×
504
                                obj.set<Int>(col, value);
×
505
                            }
×
506
                        }
×
UNCOV
507
                        else if (type == type_Bool) {
×
508
                            bool value = get_next(s) % 2 == 0;
×
509
                            if (log) {
×
510
                                *log << "obj.set<Bool>(" << col << ", " << (value ? "true" : "false") << ");\n";
×
511
                            }
×
512
                            obj.set<Bool>(col, value);
×
513
                        }
×
UNCOV
514
                        else if (type == type_Float) {
×
515
                            float value = get_next(s);
×
516
                            if (log) {
×
517
                                *log << "obj.set<Float>(" << col << ", " << value << ");\n";
×
518
                            }
×
519
                            obj.set<Float>(col, value);
×
520
                        }
×
UNCOV
521
                        else if (type == type_Double) {
×
522
                            double value = get_next(s);
×
523
                            if (log) {
×
524
                                *log << "obj.set<double>(" << col << ", " << value << ");\n";
×
525
                            }
×
526
                            obj.set<double>(col, value);
×
527
                        }
×
UNCOV
528
                        else if (type == type_Link) {
×
UNCOV
529
                            if (col.is_list()) {
×
UNCOV
530
                                TableRef target = t->get_link_target(col);
×
UNCOV
531
                                if (target->size() > 0) {
×
UNCOV
532
                                    LnkLst links = obj.get_linklist(col);
×
UNCOV
533
                                    ObjKey target_key = target->get_object(get_next(s) % target->size()).get_key();
×
534
                                    // either add or set, 50/50 probability
UNCOV
535
                                    if (links.size() > 0 && get_next(s) > 128) {
×
536
                                        size_t linklist_row = get_next(s) % links.size();
×
537
                                        if (log) {
×
538
                                            *log << "obj.get_linklist(" << col << ")->set(" << linklist_row << ", "
×
539
                                                 << target_key << ");\n";
×
540
                                        }
×
541
                                        links.set(linklist_row, target_key);
×
542
                                    }
×
UNCOV
543
                                    else {
×
UNCOV
544
                                        if (log) {
×
545
                                            *log << "obj.get_linklist(" << col << ")->add(" << target_key << ");\n";
×
546
                                        }
×
UNCOV
547
                                        links.add(target_key);
×
UNCOV
548
                                    }
×
UNCOV
549
                                }
×
UNCOV
550
                            }
×
551
                            else {
×
552
                                TableRef target = t->get_link_target(col);
×
553
                                if (target->size() > 0) {
×
554
                                    ObjKey target_key = target->get_object(get_next(s) % target->size()).get_key();
×
555
                                    if (log) {
×
556
                                        *log << "obj.set<Key>(" << col << ", " << target_key << ");\n";
×
557
                                    }
×
558
                                    obj.set(col, target_key);
×
559
                                }
×
560
                            }
×
UNCOV
561
                        }
×
562

UNCOV
563
                        else if (type == type_Timestamp) {
×
UNCOV
564
                            std::pair<int64_t, int32_t> values = get_timestamp_values(s);
×
UNCOV
565
                            Timestamp value{values.first, values.second};
×
UNCOV
566
                            if (log) {
×
567
                                *log << "obj.set(" << col << ", " << value << ");\n";
×
568
                            }
×
UNCOV
569
                            obj.set(col, value);
×
UNCOV
570
                        }
×
UNCOV
571
                    }
×
UNCOV
572
                    if (log) {
×
573
                        *log << "}\n";
×
574
                    }
×
UNCOV
575
                }
×
576
            }
8✔
577
            else if (instr == REMOVE_OBJECT && wt->size() > 0) {
775✔
578
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
17✔
579
                TableRef t = wt->get_table(table_key);
17✔
580
                if (t->size() > 0) {
17✔
581
                    ObjKey key = t->get_object(get_next(s) % t->size()).get_key();
3✔
582
                    if (log) {
3✔
583
                        *log << "wt->get_table(" << table_key << ")->remove_object(" << key << ");\n";
×
584
                    }
×
585
                    t->remove_object(key);
3✔
586
                }
3✔
587
            }
17✔
588
            else if (instr == REMOVE_RECURSIVE && wt->size() > 0) {
758✔
589
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
11✔
590
                TableRef t = wt->get_table(table_key);
11✔
591
                if (t->size() > 0) {
11✔
592
                    ObjKey key = t->get_object(get_next(s) % t->size()).get_key();
1✔
593
                    if (log) {
1✔
594
                        *log << "wt->get_table(" << table_key << ")->remove_object_recursive(" << key << ");\n";
×
595
                    }
×
596
                    t->remove_object_recursive(key);
1✔
597
                }
1✔
598
            }
11✔
599
            else if (instr == ENUMERATE_COLUMN && wt->size() > 0) {
747✔
600
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
16✔
601
                TableRef t = wt->get_table(table_key);
16✔
602
                auto all_col_keys = t->get_column_keys();
16✔
603
                if (!all_col_keys.empty()) {
16✔
604
                    size_t ndx = get_next(s) % all_col_keys.size();
5✔
605
                    ColKey col = all_col_keys[ndx];
5✔
606
                    if (log) {
5✔
607
                        *log << "wt->get_table(" << table_key << ")->enumerate_string_column(" << col << ");\n";
×
608
                    }
×
609
                    wt->get_table(table_key)->enumerate_string_column(col);
5✔
610
                }
5✔
611
            }
16✔
612
            else if (instr == COMMIT) {
731✔
613
                if (log) {
41✔
614
                    *log << "wt->commit_and_continue_as_read();\n";
×
615
                }
×
616
                wt->commit_and_continue_as_read();
41✔
617
                REALM_DO_IF_VERIFY(log, wt->verify());
41✔
618
                if (log) {
41✔
619
                    *log << "wt->promote_to_write();\n";
×
620
                }
×
621
                wt->promote_to_write();
41✔
622
                REALM_DO_IF_VERIFY(log, wt->verify());
41✔
623
            }
41✔
624
            else if (instr == ROLLBACK) {
690✔
625
                if (log) {
31✔
626
                    *log << "wt->rollback_and_continue_as_read();\n";
×
627
                }
×
628
                wt->rollback_and_continue_as_read();
31✔
629
                REALM_DO_IF_VERIFY(log, wt->verify());
31✔
630
                if (log) {
31✔
631
                    *log << "wt->promote_to_write();\n";
×
632
                }
×
633
                wt->promote_to_write();
31✔
634
                REALM_DO_IF_VERIFY(log, wt->verify());
31✔
635
            }
31✔
636
            else if (instr == ADVANCE) {
659✔
637
                if (log) {
32✔
638
                    *log << "rt->advance_read();\n";
×
639
                }
×
640
                rt->advance_read();
32✔
641
                REALM_DO_IF_VERIFY(log, rt->verify());
32✔
642
            }
32✔
643
            else if (instr == CLOSE_AND_REOPEN) {
627✔
644
                if (log) {
42✔
645
                    *log << "wt = nullptr;\n";
×
646
                    *log << "rt = nullptr;\n";
×
647
                    *log << "db->close();\n";
×
648
                }
×
649
                wt = nullptr; // transactions must be done/closed before closing the DB.
42✔
650
                rt = nullptr;
42✔
651
                db->close();
42✔
652
                if (log) {
42✔
653
                    *log << "db = DB::create(*hist, path, DBOptions(key));\n";
×
654
                }
×
655
                db = DB::create(*hist, path, DBOptions(encryption_key));
42✔
656
                if (log) {
42✔
657
                    *log << "wt = db_w->start_write();\n";
×
658
                    *log << "rt = db->start_read();\n";
×
659
                }
×
660
                rt = db->start_read();
42✔
661
                wt = db->start_write();
42✔
662
                REALM_DO_IF_VERIFY(log, rt->verify());
42✔
663
            }
42✔
664
            else if (instr == GET_ALL_COLUMN_NAMES && wt->size() > 0) {
585✔
665
                // try to fuzz find this: https://github.com/realm/realm-core/issues/1769
666
                for (auto table_key : wt->get_table_keys()) {
26✔
667
                    TableRef t = wt->get_table(table_key);
26✔
668
                    auto all_col_keys = t->get_column_keys();
26✔
669
                    for (auto col : all_col_keys) {
26✔
670
                        StringData col_name = t->get_column_name(col);
15✔
671
                        static_cast<void>(col_name);
15✔
672
                    }
15✔
673
                }
26✔
674
            }
15✔
675
            else if (instr == CREATE_TABLE_VIEW && wt->size() > 0) {
570✔
676
                TableKey table_key = wt->get_table_keys()[get_next(s) % wt->size()];
7✔
677
                TableRef t = wt->get_table(table_key);
7✔
678
                if (log) {
7✔
679
                    *log << "table_views.push_back(wt->get_table(" << table_key << ")->where().find_all());\n";
×
680
                }
×
681
                TableView tv = t->where().find_all();
7✔
682
                table_views.push_back(tv);
7✔
683
            }
7✔
684
            else if (instr == COMPACT) {
563✔
685
                /*
686
                if (log) {
687
                    *log << "db_r.close();\n";
688
                }
689
                db_r.close();
690
                if (log) {
691
                    *log << "wt->commit();\n";
692
                }
693
                wt->commit();
694

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

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

737

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

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

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

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

784
    disable_sync_to_disk();
×
785

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

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

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

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

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

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

821
    return 0;
×
822
}
×
823
#else
824
int run_fuzzy(int, const char*[])
825
{
826
    return 0;
827
}
828
#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