• 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

78.46
/test/test_all.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
// #define USE_VLD
20
#if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_VLD)
21
#include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h"
22
#endif
23

24
#include <ctime>
25
#include <cstring>
26
#include <cstdlib>
27
#include <algorithm>
28
#include <stdexcept>
29
#include <tuple>
30
#include <memory>
31
#include <iterator>
32
#include <vector>
33
#include <locale>
34
#include <sstream>
35
#include <fstream>
36
#include <iostream>
37
#include <iomanip>
38
#include <thread>
39

40
#include <realm/util/features.h>
41
#include <realm/util/platform_info.hpp>
42
#include <realm.hpp>
43
#include <realm/utilities.hpp>
44
#include <realm/disable_sync_to_disk.hpp>
45

46
#include "util/timer.hpp"
47
#include "util/resource_limits.hpp"
48

49
#include "test.hpp"
50
#include "test_all.hpp"
51

52
#ifdef _WIN32
53
#include <Windows.h>
54
#if REALM_UWP
55
#include <winrt/Windows.ApplicationModel.h>
56
#include <winrt/Windows.Storage.h>
57
#else
58
// PathCchRemoveFileSpec()
59
#include <pathcch.h>
60
#pragma comment(lib, "Pathcch.lib")
61
#endif
62
#endif
63

64
// Need to disable file descriptor leak checks on Apple platforms, as it seems
65
// like an unknown number of file descriptors can be left behind, presumably due
66
// the way asynchronous DNS lookup is implemented.
67
#if !defined _WIN32 && !REALM_PLATFORM_APPLE
68
#define ENABLE_FILE_DESCRIPTOR_LEAK_CHECK
69
#endif
70

71
#ifdef ENABLE_FILE_DESCRIPTOR_LEAK_CHECK
72
#include <unistd.h>
73
#include <fcntl.h>
74
#endif
75

76
using namespace realm;
77
using namespace realm::test_util;
78
using namespace realm::test_util::unit_test;
79

80
// Random seed for various random number generators used by fuzzying unit tests.
81
unsigned int unit_test_random_seed;
82

83
namespace {
84

85
// clang-format off
86
const char* file_order[] = {
87
    // When choosing order, please try to use these guidelines:
88
    //
89
    //  - If feature A depends on feature B, test feature B first.
90
    //
91
    //  - If feature A has a more central role in the API than feature B, test
92
    //    feature A first.
93
    //
94
    "test_self.cpp",
95

96
    // realm/util/
97
    "test_safe_int_ops.cpp",
98
    "test_basic_utils.cpp",
99
    "test_file*.cpp",
100
    "test_thread.cpp",
101
    "test_util_network.cpp",
102
    "test_utf8.cpp",
103

104
    // /realm/ (helpers)
105
    "test_string_data.cpp",
106
    "test_binary_data.cpp",
107

108
    // /realm/impl/ (detail)
109
    "test_alloc*.cpp",
110
    "test_array*.cpp",
111
    "test_column*.cpp",
112
    "test_index*.cpp",
113
    "test_destroy_guard.cpp",
114

115
    // /realm/ (main API)
116
    "test_table*.cpp",
117
    "test_descriptor*.cpp",
118
    "test_group*.cpp",
119
    "test_shared*.cpp",
120
    "test_transactions*.cpp",
121
    "test_query*.cpp",
122
    "test_links.cpp",
123
    "test_link_query_view.cpp",
124
    "test_json.cpp",
125
    "test_replication*.cpp",
126

127
    "test_lang_bind_helper.cpp",
128

129
    "large_tests*.cpp",
130
    "test_crypto.cpp",
131
    "test_transform.cpp",
132
    "test_array.cpp",
133
    "test_lang_bind_helper_sync.cpp",
134
    "test_sync.cpp",
135
    "test_backup.cpp",
136
    "test_sync_fuzz.cpp"
137
};
138
// clang-format on
139

140
void fix_max_open_files()
141
{
8✔
142
    if (system_has_rlimit(resource_NumOpenFiles)) {
8✔
143
        long soft_limit = get_soft_rlimit(resource_NumOpenFiles);
8✔
144
        if (soft_limit >= 0) {
8✔
145
            long hard_limit = get_hard_rlimit(resource_NumOpenFiles);
8✔
146
            long new_soft_limit = hard_limit < 0 ? 4096 : hard_limit;
8✔
147
            if (new_soft_limit > soft_limit) {
8✔
148
                set_soft_rlimit(resource_NumOpenFiles, new_soft_limit);
×
149
                /*
150
                std::cout << "\n"
151
                    "MaxOpenFiles: "<<soft_limit<<" --> "<<new_soft_limit<<"\n";
152
                */
153
            }
×
154
        }
8✔
155
    }
8✔
156
}
8✔
157

158

159
long get_num_open_files()
160
{
12✔
161
#ifdef ENABLE_FILE_DESCRIPTOR_LEAK_CHECK
8✔
162
    if (system_has_rlimit(resource_NumOpenFiles)) {
8✔
163
        long soft_limit = get_soft_rlimit(resource_NumOpenFiles);
8✔
164
        if (soft_limit >= 0) {
8✔
165
            long num_open_files = 0;
8✔
166
            for (long i = 0; i < soft_limit; ++i) {
512,008✔
167
                int fildes = int(i);
512,000✔
168
                int ret = fcntl(fildes, F_GETFD);
512,000✔
169
                if (ret != -1) {
512,000✔
170
                    ++num_open_files;
32✔
171
                    continue;
32✔
172
                }
32✔
173
                if (errno != EBADF)
511,968✔
174
                    throw std::runtime_error("fcntl() failed");
511,968✔
175
            }
511,968✔
176
            return num_open_files;
8✔
177
        }
178
    }
8✔
179
#endif
180
    return -1;
4✔
181
}
4✔
182

183
void set_random_seed()
184
{
8✔
185
    // Select random seed for the random generator that some of our unit tests are using
4✔
186
    const char* str = getenv("UNITTEST_RANDOM_SEED");
8✔
187
    if (str && strlen(str) != 0 && strcmp(str, "random") != 0) {
8!
188
        std::istringstream in(str);
×
189
        in.imbue(std::locale::classic());
×
190
        in.flags(in.flags() & ~std::ios_base::skipws); // Do not accept white space
×
191
        in >> unit_test_random_seed;
×
192
        bool bad = !in || in.get() != std::char_traits<char>::eof();
×
193
        if (bad)
×
194
            throw std::runtime_error("Bad random seed");
×
195
    }
8✔
196
    else {
8✔
197
        unit_test_random_seed = produce_nondeterministic_random_seed();
8✔
198
    }
8✔
199
    random_seed(unit_test_random_seed);
8✔
200
}
8✔
201

202
class AggressiveGovernor : public util::PageReclaimGovernor {
203
public:
204
    util::UniqueFunction<int64_t()> current_target_getter(size_t) override
205
    {
×
206
        return []() { return 4096; };
×
207
    }
×
208
    void report_target_result(int64_t) override {}
×
209
};
210

211
AggressiveGovernor aggressive_governor;
212

213
void set_always_encrypt()
214
{
8✔
215
    if (const char* env = getenv("UNITTEST_ENCRYPT_ALL")) {
8✔
216
        std::string str(env);
×
217
        for (auto& c : str) {
×
218
            c = tolower(c);
×
219
        }
×
220
        if (str == "1" || str == "on" || str == "yes") {
×
221
            enable_always_encrypt();
×
222
            // ask for a very aggressive page reclaimer to maximize chance of triggering a bug.
223
            realm::util::set_page_reclaim_governor(&aggressive_governor);
×
224
        }
×
225
    }
×
226
}
8✔
227

228
void display_build_config()
229
{
8✔
230
    const char* with_debug = Version::has_feature(feature_Debug) ? "Enabled" : "Disabled";
8✔
231

4✔
232
#if REALM_ENABLE_MEMDEBUG
233
    const char* memdebug = "Enabled";
234
#else
235
    const char* memdebug = "Disabled";
8✔
236
#endif
8✔
237

4✔
238
#if REALM_ENABLE_ENCRYPTION
8✔
239
    bool always_encrypt = is_always_encrypt_enabled();
8✔
240
    const char* encryption = always_encrypt ? "Enabled at compile-time (always encrypt = yes)"
4✔
241
                                            : "Enabled at compile-time (always encrypt = no)";
8✔
242
#else
243
    const char* encryption = "Disabled at compile-time";
244
#endif
245

4✔
246
#ifdef REALM_COMPILER_SSE
4✔
247
    const char* compiler_sse = "Yes";
4✔
248
#else
249
    const char* compiler_sse = "No";
4✔
250
#endif
4✔
251

4✔
252
#ifdef REALM_COMPILER_AVX
4✔
253
    const char* compiler_avx = "Yes";
4✔
254
#else
255
    const char* compiler_avx = "No";
4✔
256
#endif
4✔
257

4✔
258
    const char* cpu_sse = realm::sseavx<42>() ? "4.2" : (realm::sseavx<30>() ? "3.0" : "None");
8✔
259

4✔
260
    const char* cpu_avx = realm::sseavx<1>() ? "Yes" : "No";
8✔
261

4✔
262
    std::cout << std::endl
8✔
263
              << "Realm version: " << Version::get_version() << " with Debug " << with_debug << "\n"
8✔
264
              << "Platform: " << util::get_platform_info() << "\n"
8✔
265
              << "Encryption: " << encryption << "\n"
8✔
266
              << "\n"
8✔
267
              << "REALM_MAX_BPNODE_SIZE = " << REALM_MAX_BPNODE_SIZE << "\n"
8✔
268
              << "REALM_MEMDEBUG = " << memdebug << "\n"
8✔
269
              << "\n"
8✔
270
              // Be aware that ps3/xbox have sizeof (void*) = 4 && sizeof (size_t) == 8
4✔
271
              // We decide to print size_t here
4✔
272
              << "sizeof (size_t) * 8 = " << (sizeof(size_t) * 8) << "\n"
8✔
273
              << "\n"
8✔
274
              << "Compiler supported SSE (auto detect):       " << compiler_sse << "\n"
8✔
275
              << "This CPU supports SSE (auto detect):        " << cpu_sse << "\n"
8✔
276
              << "Compiler supported AVX (auto detect):       " << compiler_avx << "\n"
8✔
277
              << "This CPU supports AVX (AVX1) (auto detect): " << cpu_avx << "\n"
8✔
278
              << "\n"
8✔
279
              << "UNITTEST_RANDOM_SEED:                       " << unit_test_random_seed << "\n"
8✔
280
              << "Test path prefix:                           " << test_util::get_test_path_prefix() << "\n"
8✔
281
              << "Test resource path:                         " << test_util::get_test_resource_path() << "\n"
8✔
282
              << std::endl;
8✔
283
}
8✔
284

285

286
// Records elapsed time for each test and shows a "Top 5" at the end.
287
class CustomReporter : public SimpleReporter {
288
public:
289
    explicit CustomReporter(bool report_progress)
290
        : SimpleReporter(report_progress)
291
    {
8✔
292
    }
8✔
293

294
    ~CustomReporter() noexcept
295
    {
8✔
296
    }
8✔
297

298
    void end(const TestContext& context, double elapsed_seconds) override
299
    {
7,818✔
300
        result r;
7,818✔
301
        r.test_index = context.test_index;
7,818✔
302
        r.recurrence_index = context.recurrence_index;
7,818✔
303
        r.elapsed_seconds = elapsed_seconds;
7,818✔
304
        m_results.push_back(r);
7,818✔
305
        SimpleReporter::end(context, elapsed_seconds);
7,818✔
306
    }
7,818✔
307

308
    void summary(const SharedContext& context, const Summary& results_summary) override
309
    {
8✔
310
        SimpleReporter::summary(context, results_summary);
8✔
311

4✔
312
        size_t max_n = 5;
8✔
313
        size_t n = std::min<size_t>(max_n, m_results.size());
8✔
314
        if (n < 2)
8✔
315
            return;
×
316

4✔
317
        partial_sort(m_results.begin(), m_results.begin() + n, m_results.end());
8✔
318
        std::vector<std::tuple<std::string, std::string>> rows;
8✔
319
        size_t name_col_width = 0, time_col_width = 0;
8✔
320
        for (size_t i = 0; i < n; ++i) {
48✔
321
            const result& r = m_results[i];
40✔
322
            const TestDetails& details = context.test_list.get_test_details(r.test_index);
40✔
323
            std::ostringstream out;
40✔
324
            out.imbue(std::locale::classic());
40✔
325
            out << details.test_name;
40✔
326
            if (context.num_recurrences > 1)
40✔
327
                out << '#' << (r.recurrence_index + 1);
×
328
            std::string name = out.str();
40✔
329
            std::string time = Timer::format(r.elapsed_seconds);
40✔
330
            rows.emplace_back(name, time);
40✔
331
            if (name.size() > name_col_width)
40✔
332
                name_col_width = name.size();
18✔
333
            if (time.size() > time_col_width)
40✔
334
                time_col_width = time.size();
12✔
335
        }
40✔
336

4✔
337
        name_col_width += 2;
8✔
338
        size_t full_width = name_col_width + time_col_width;
8✔
339
        std::cout.fill('-');
8✔
340
        std::cout << "\nTop " << n << " time usage:\n"
8✔
341
                  << std::setw(int(full_width)) << ""
8✔
342
                  << "\n";
8✔
343
        std::cout.fill(' ');
8✔
344
        for (const auto& row : rows) {
40✔
345
            std::cout << std::left << std::setw(int(name_col_width)) << std::get<0>(row) << std::right
40✔
346
                      << std::setw(int(time_col_width)) << std::get<1>(row) << "\n";
40✔
347
        }
40✔
348
    }
8✔
349

350
private:
351
    struct result {
352
        size_t test_index;
353
        int recurrence_index;
354
        double elapsed_seconds;
355
        bool operator<(const result& r) const
356
        {
9,230✔
357
            return elapsed_seconds > r.elapsed_seconds; // Descending order
9,230✔
358
        }
9,230✔
359
    };
360

361
    std::vector<result> m_results;
362
};
363

364

365
void put_time(std::ostream& out, const std::tm& tm, const char* format)
366
{
×
367
    const std::time_put<char>& facet = std::use_facet<std::time_put<char>>(out.getloc());
×
368
    facet.put(std::ostreambuf_iterator<char>(out), out, ' ', &tm, format, format + strlen(format));
×
369
}
×
370

371

372
bool run_tests(const std::shared_ptr<realm::util::Logger>& logger = nullptr)
373
{
8✔
374
    {
8✔
375
        const char* str = getenv("UNITTEST_KEEP_FILES");
8✔
376
        if (str && strlen(str) != 0)
8!
377
            keep_test_files();
×
378
    }
8✔
379
    const bool running_spawned_process = getenv("REALM_SPAWNED");
8✔
380

4✔
381
    TestList::Config config;
8✔
382
    config.logger = logger;
8✔
383

4✔
384
    // Log timestamps
4✔
385
    {
8✔
386
        const char* str = getenv("UNITTEST_LOG_TIMESTAMPS");
8✔
387
        if (str && std::strlen(str) != 0)
8!
388
            config.log_timestamps = true;
×
389
    }
8✔
390

4✔
391
    // Set number of threads
4✔
392
    {
8✔
393
        const char* str = getenv("UNITTEST_THREADS");
8✔
394
        if (str && strlen(str) != 0) {
8!
395
            std::istringstream in(str);
×
396
            in.imbue(std::locale::classic());
×
397
            in.flags(in.flags() & ~std::ios_base::skipws); // Do not accept white space
×
398
            in >> config.num_threads;
×
399
            bool bad = !in || in.get() != std::char_traits<char>::eof() || config.num_threads < 1;
×
400
            if (bad)
×
401
                throw std::runtime_error("Bad number of threads");
×
402
            if (config.num_threads > 1 && !running_spawned_process)
×
403
                std::cout << "Number of test threads: " << config.num_threads << "\n\n";
×
404
        }
×
405
        else {
8✔
406
            config.num_threads = std::thread::hardware_concurrency();
8✔
407
            if (!running_spawned_process) {
8✔
408
                std::cout << "Number of test threads: " << config.num_threads << " (default)\n";
8✔
409
                std::cout << "(Use UNITTEST_THREADS=1 to serialize testing) \n\n";
8✔
410
            }
8✔
411
        }
8✔
412
    }
8✔
413

4✔
414
    // Set number of repetitions
4✔
415
    {
8✔
416
        const char* str = getenv("UNITTEST_REPEAT");
8✔
417
        if (str && strlen(str) != 0) {
8!
418
            std::istringstream in(str);
×
419
            in.imbue(std::locale::classic());
×
420
            in.flags(in.flags() & ~std::ios_base::skipws); // Do not accept white space
×
421
            in >> config.num_repetitions;
×
422
            bool bad = !in || in.get() != std::char_traits<char>::eof() || config.num_repetitions < 0;
×
423
            if (bad)
×
424
                throw std::runtime_error("Bad number of repetitions");
×
425
        }
8✔
426
    }
8✔
427

4✔
428
    // Shuffle
4✔
429
    {
8✔
430
        const char* str = getenv("UNITTEST_SHUFFLE");
8✔
431
        if (config.num_threads > 1 || (str && strlen(str) != 0))
8!
432
            config.shuffle = true;
8✔
433
    }
8✔
434

4✔
435
    // Set up reporter
4✔
436
    util::File junit_file;
8✔
437
    util::File::Streambuf junit_streambuf(&junit_file);
8✔
438
    std::ostream junit_out(&junit_streambuf);
8✔
439
    std::vector<std::unique_ptr<Reporter>> reporters;
8✔
440
    {
8✔
441
        const char* str = getenv("UNITTEST_PROGRESS");
8✔
442
        bool report_progress = str && strlen(str) != 0;
8✔
443
        reporters.push_back(std::make_unique<CustomReporter>(report_progress));
8✔
444
    }
8✔
445
    if (const char* str = getenv("UNITTEST_XML"); str && strlen(str) != 0) {
8!
446
        std::cout << "Configuring jUnit reporter to store test results in " << str << std::endl;
×
447
        junit_file.open(str, util::File::mode_Write);
×
448
        const char* test_suite_name = getenv("UNITTEST_SUITE_NAME");
×
449
        if (!test_suite_name || !strlen(test_suite_name))
×
450
            test_suite_name = "realm-core-tests";
×
451
        reporters.push_back(create_junit_reporter(junit_out, test_suite_name));
×
452
    }
×
453
    else if (const char* str = getenv("UNITTEST_EVERGREEN_TEST_RESULTS"); str && strlen(str) != 0) {
8✔
454
        std::cout << "Configuring evergreen reporter to store test results in " << str << std::endl;
8✔
455
        reporters.push_back(create_evergreen_reporter(str));
8✔
456
    }
8✔
457
    auto reporter = create_combined_reporter(reporters);
8✔
458
    config.reporter = reporter.get();
8✔
459

4✔
460
    // Set up filter
4✔
461
    const char* filter_str = getenv("UNITTEST_FILTER");
8✔
462
    const char* test_only = get_test_only();
8✔
463
    if (test_only)
8✔
464
        filter_str = test_only;
×
465
    std::unique_ptr<Filter> filter;
8✔
466
    if (filter_str && strlen(filter_str) != 0)
8!
467
        filter = create_wildcard_filter(filter_str);
×
468
    config.filter = filter.get();
8✔
469

4✔
470
    // Set intra test log level threshold
4✔
471
    {
8✔
472
        const char* str = getenv("UNITTEST_LOG_LEVEL");
8✔
473
        if (str && *str) {
8!
NEW
474
            if (auto level = realm::util::Logger::level_from_string(str)) {
×
NEW
475
                config.intra_test_log_level = *level;
×
NEW
476
            }
×
NEW
477
            else {
×
NEW
478
                throw std::runtime_error(util::format("Invalid log level '%1'", str));
×
NEW
479
            }
×
480
        }
8✔
481
    }
8✔
482

4✔
483
    // Set up per-thread file logging
4✔
484
    {
8✔
485
        const char* str = getenv("UNITTEST_LOG_TO_FILES");
8✔
486
        if (str && strlen(str) != 0) {
8!
487
            std::ostringstream out;
×
488
            out.imbue(std::locale::classic());
×
489
            time_t now = time(nullptr);
×
490
            tm tm = *localtime(&now);
×
491
            out << "test_logs_";
×
492
            put_time(out, tm, "%Y%m%d_%H%M%S");
×
493
            std::string dir_path = get_test_path_prefix() + out.str();
×
494
            util::make_dir(dir_path);
×
495
            config.per_thread_log_path = util::File::resolve("thread_%.log", dir_path);
×
496
        }
×
497
    }
8✔
498

4✔
499
    // Enable abort on failure
4✔
500
    {
8✔
501
        const char* str = getenv("UNITTEST_ABORT_ON_FAILURE");
8✔
502
        if (str && strlen(str) != 0) {
8!
503
            config.abort_on_failure = true;
×
504
        }
×
505
    }
8✔
506

4✔
507
    // Run
4✔
508
    TestList& list = get_default_test_list();
8✔
509
    list.sort(PatternBasedFileOrder(file_order));
8✔
510
    bool success = list.run(config);
8✔
511

4✔
512
    if (test_only)
8✔
513
        std::cout << "\n*** BE AWARE THAT MOST TESTS WERE EXCLUDED DUE TO USING 'ONLY' MACRO ***\n";
×
514

4✔
515
    std::cout << "\n";
8✔
516

4✔
517
    // The iOS Simulator has a separate set of kernel file caches from the parent
4✔
518
    // OS, and if the simulator is deleted immediately after running the tests
4✔
519
    // (as is done on CI), the writes never actually make it to disk without
4✔
520
    // an explicit F_FULLFSYNC.
4✔
521
    if (junit_file.is_attached()) {
8✔
522
        junit_out.flush();
×
523
        junit_file.sync();
×
524
    }
×
525

4✔
526
    return success;
8✔
527
}
8✔
528

529
} // anonymous namespace
530

531

532
int test_all(const std::shared_ptr<realm::util::Logger>& logger)
533
{
8✔
534
    // General note: Some Github clients on Windows will interfere with the .realm files created by unit tests (the
4✔
535
    // git client will attempt to access the files when it sees that new files have been created). This may cause
4✔
536
    // very rare/sporadic segfaults and asserts. If the temporary directory path is outside revision control, there
4✔
537
    // is no problem. Otherwise we need two things fulfilled: 1) The directory must be in .gitignore, and also 2)
4✔
538
    // The directory must be newly created and not added to git.
4✔
539

4✔
540
    // Disable buffering on std::cout so that progress messages can be related to
4✔
541
    // error messages.
4✔
542
    std::cout.setf(std::ios::unitbuf);
8✔
543

4✔
544
#ifndef REALM_COVER
8✔
545
    // No need to synchronize file changes to physical medium in the test suite,
4✔
546
    // as that would only make a difference if the entire system crashes,
4✔
547
    // e.g. due to power off.
4✔
548
    // NOTE: This is not strictly true. If encryption is enabled, a crash of the testsuite
4✔
549
    // (not the whole platform) may produce corrupt realm files.
4✔
550
    char* enable_sync_to_disk = getenv("UNITTEST_ENABLE_SYNC_TO_DISK");
8✔
551
    if (!enable_sync_to_disk)
8✔
552
        disable_sync_to_disk();
8✔
553
#endif
8✔
554

4✔
555
    char* no_error_exitcode_str = getenv("UNITTEST_NO_ERROR_EXITCODE");
8✔
556
    bool no_error_exit_status = no_error_exitcode_str && strlen(no_error_exitcode_str) != 0;
8!
557

4✔
558
#ifdef WIN32
559
#if REALM_UWP
560
    std::string path =
561
        winrt::to_string(winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path());
562
    path += "\\TestAssets\\";
563
    set_test_resource_path(path);
564
    set_test_path_prefix(path);
565
#endif
566
#endif
567

4✔
568
    set_random_seed();
8✔
569
    set_always_encrypt();
8✔
570

4✔
571
    fix_max_open_files();
8✔
572

4✔
573
    if (!getenv("REALM_SPAWNED"))
8✔
574
        display_build_config();
8✔
575

4✔
576
    long num_open_files = get_num_open_files();
8✔
577

4✔
578
    bool success = run_tests(logger);
8✔
579

4✔
580
    if (num_open_files >= 0) {
8✔
581
        long num_open_files_2 = get_num_open_files();
4✔
582
        REALM_ASSERT(num_open_files_2 >= 0);
4!
583
        if (num_open_files_2 > num_open_files) {
4!
584
            long n = num_open_files_2 - num_open_files;
×
585
            // FIXME: This should be an error, but OpenSSL seems to open
586
            // files behind our back, and calling OPENSSL_cleanup() does not
587
            // seem to have any effect.
588
            std::cerr << "WARNING: " << n << " file descriptors were leaked\n";
×
589
            // success = false;
590
        }
×
591
    }
4✔
592

4✔
593
#ifdef _MSC_VER
594
    // We don't want spawned processes (see spawned_process.hpp to require user interaction).
595
    if (!getenv("REALM_SPAWNED"))
596
        getchar(); // wait for key
597
#endif
598

4✔
599
    return success || no_error_exit_status ? EXIT_SUCCESS : EXIT_FAILURE;
8!
600
}
8✔
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