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

realm / realm-core / jonathan.reams_3577

21 Jan 2025 05:41PM UTC coverage: 91.105% (-0.02%) from 91.124%
jonathan.reams_3577

Pull #8064

Evergreen

jbreams
fix test
Pull Request #8064: Sync access token refreshes shouldn't extend SyncSession lifetime

102714 of 181514 branches covered (56.59%)

73 of 73 new or added lines in 3 files covered. (100.0%)

109 existing lines in 18 files now uncovered.

217338 of 238558 relevant lines covered (91.1%)

5558106.05 hits per line

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

46.57
/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/disable_sync_to_disk.hpp>
23
#include <realm/index_string.hpp>
24

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

30
#include "util/test_path.hpp"
31

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

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

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

54
namespace {
55

56
struct EndOfFile {};
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
{
11✔
89
    DataType types[] = {type_Int, type_Bool, type_Float, type_Double, type_String, type_Binary, type_Timestamp};
11✔
90

91
    unsigned char mod = c % (sizeof(types) / sizeof(DataType));
11✔
92
    return types[mod];
11✔
93
}
11✔
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,206✔
109

110
const char* get_encryption_key()
111
{
3✔
112
#if REALM_ENABLE_ENCRYPTION
3✔
113
    return "1234567890123456789012345678901123456789012345678901234567890123";
3✔
114
#else
115
    return nullptr;
116
#endif
117
}
3✔
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
{
1✔
131
    int32_t v = 0;
1✔
132
    for (size_t t = 0; t < 4; t++) {
5✔
133
        unsigned char c = get_next(s);
4✔
134
        *(reinterpret_cast<signed char*>(&v) + t) = c;
4✔
135
    }
4✔
136
    return v;
1✔
137
}
1✔
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
{
38✔
167
    std::string str;
38✔
168
    switch (t) {
38✔
169
        case type_Int:
1✔
170
            str = "int_";
1✔
171
            break;
1✔
172
        case type_Bool:
2✔
173
            str = "bool_";
2✔
174
            break;
2✔
175
        case type_Float:
5✔
176
            str = "float_";
5✔
177
            break;
5✔
178
        case type_Double:
1✔
179
            str = "double_";
1✔
180
            break;
1✔
181
        case type_String:
2✔
182
            str = "string_";
2✔
183
            break;
2✔
184
        case type_Binary:
1✔
185
            str = "binary_";
1✔
186
            break;
1✔
187
        case type_Timestamp:
1✔
188
            str = "date_";
1✔
189
            break;
1✔
190
        case type_Decimal:
✔
191
            str = "decimal_";
×
192
            break;
×
193
        case type_ObjectId:
✔
194
            str = "id_";
×
195
            break;
×
196
        case type_Link:
25✔
197
            str = "link_";
25✔
198
            break;
25✔
199
        case type_TypedLink:
✔
200
            str = "typed_link_";
×
201
            break;
×
202
        case type_UUID:
✔
203
            str = "uuid_";
×
204
            break;
×
205
        case type_Mixed:
✔
206
            str = "any_";
×
207
            break;
×
208
    }
38✔
209
    return str + util::to_string(column_index++);
38✔
210
}
38✔
211

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

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

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

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

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

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

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

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

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

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

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

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

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

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

283
    try {
6✔
284

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

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

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

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

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

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

701
                if (log) {
702
                    *log << "wt = db_w.start_write();\n";
703
                }
704
                wt = db_w.start_write();
705
                if (log) {
706
                    *log << "db_r.open(path, true, DBOptions(key));\n";
707
                }
708
                db_r.open(path, true, DBOptions(encryption_key));
709
                if (log) {
710
                    *log << "rt = db_r.start_read();\n";
711
                }
712
                rt = db_r.start_read();
713
                REALM_DO_IF_VERIFY(log, rt->verify());
714
                */
715
            }
30✔
716
            else if (instr == IS_NULL && rt->size() > 0) {
445✔
717
                TableKey table_key = rt->get_table_keys()[get_next(s) % rt->size()];
7✔
718
                TableRef t = rt->get_table(table_key);
7✔
719
                if (t->get_column_count() > 0 && t->size() > 0) {
7✔
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
            }
7✔
732
        }
882✔
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