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

realm / realm-core / kirill.burtsev_130

14 Feb 2024 07:28PM UTC coverage: 91.891% (+0.01%) from 91.881%
kirill.burtsev_130

Pull #7344

Evergreen

kiburtse
fix some gcc build warnings
Pull Request #7344: Allow to set logging level through env var for object store tests

93086 of 171520 branches covered (54.27%)

36 of 40 new or added lines in 5 files covered. (90.0%)

47 existing lines in 10 files now uncovered.

235529 of 256314 relevant lines covered (91.89%)

6267890.8 hits per line

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

79.25
/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,914✔
300
        result r;
7,914✔
301
        r.test_index = context.test_index;
7,914✔
302
        r.recurrence_index = context.recurrence_index;
7,914✔
303
        r.elapsed_seconds = elapsed_seconds;
7,914✔
304
        m_results.push_back(r);
7,914✔
305
        SimpleReporter::end(context, elapsed_seconds);
7,914✔
306
    }
7,914✔
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();
16✔
333
            if (time.size() > time_col_width)
40✔
334
                time_col_width = time.size();
8✔
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,318✔
357
            return elapsed_seconds > r.elapsed_seconds; // Descending order
9,318✔
358
        }
9,318✔
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!
NEW
446
        if (!running_spawned_process)
×
NEW
447
            std::cout << "Configuring jUnit reporter to store test results in " << str << std::endl;
×
448
        junit_file.open(str, util::File::mode_Write);
×
449
        const char* test_suite_name = getenv("UNITTEST_SUITE_NAME");
×
450
        if (!test_suite_name || !strlen(test_suite_name))
×
451
            test_suite_name = "realm-core-tests";
×
452
        reporters.push_back(create_junit_reporter(junit_out, test_suite_name));
×
453
    }
×
454
    else if (const char* str = getenv("UNITTEST_EVERGREEN_TEST_RESULTS"); str && strlen(str) != 0) {
8✔
455
        if (!running_spawned_process)
8✔
456
            std::cout << "Configuring evergreen reporter to store test results in " << str << std::endl;
8✔
457
        reporters.push_back(create_evergreen_reporter(str));
8✔
458
    }
8✔
459
    auto reporter = create_combined_reporter(reporters);
8✔
460
    if (!running_spawned_process)
8✔
461
        config.reporter = reporter.get();
8✔
462

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

4✔
473
    // Set intra test log level threshold
4✔
474
    if (!util::Logger::get_env_log_level_if_set(config.intra_test_log_level))
8✔
NEW
475
        throw std::runtime_error("Bad intra test log level");
×
476

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

4✔
493
    // Enable abort on failure
4✔
494
    {
8✔
495
        const char* str = getenv("UNITTEST_ABORT_ON_FAILURE");
8✔
496
        if (str && strlen(str) != 0) {
8!
497
            config.abort_on_failure = true;
×
498
        }
×
499
    }
8✔
500

4✔
501
    // Run
4✔
502
    TestList& list = get_default_test_list();
8✔
503
    list.sort(PatternBasedFileOrder(file_order));
8✔
504
    bool success = list.run(config);
8✔
505

4✔
506
    if (test_only && !running_spawned_process)
8!
507
        std::cout << "\n*** BE AWARE THAT MOST TESTS WERE EXCLUDED DUE TO USING 'ONLY' MACRO ***\n";
×
508

4✔
509
    if (!running_spawned_process)
8✔
510
        std::cout << "\n";
8✔
511

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

4✔
521
    return success;
8✔
522
}
8✔
523

524
} // anonymous namespace
525

526

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

4✔
535
    // Disable buffering on std::cout so that progress messages can be related to
4✔
536
    // error messages.
4✔
537
    std::cout.setf(std::ios::unitbuf);
8✔
538

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

4✔
550
    char* no_error_exitcode_str = getenv("UNITTEST_NO_ERROR_EXITCODE");
8✔
551
    bool no_error_exit_status = no_error_exitcode_str && strlen(no_error_exitcode_str) != 0;
8!
552

4✔
553
#ifdef WIN32
554
#if REALM_UWP
555
    std::string path =
556
        winrt::to_string(winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path());
557
    path += "\\TestAssets\\";
558
    set_test_resource_path(path);
559
    set_test_path_prefix(path);
560
#endif
561
#endif
562

4✔
563
    set_random_seed();
8✔
564
    set_always_encrypt();
8✔
565

4✔
566
    fix_max_open_files();
8✔
567

4✔
568
    if (!getenv("REALM_SPAWNED"))
8✔
569
        display_build_config();
8✔
570

4✔
571
    long num_open_files = get_num_open_files();
8✔
572

4✔
573
    bool success = run_tests(logger);
8✔
574

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

4✔
588
#ifdef _MSC_VER
589
    // We don't want spawned processes (see spawned_process.hpp to require user interaction).
590
    if (!getenv("REALM_SPAWNED"))
591
        getchar(); // wait for key
592
#endif
593

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

© 2026 Coveralls, Inc