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

realm / realm-core / 2429

18 Jun 2024 04:04PM UTC coverage: 90.969% (-0.03%) from 90.996%
2429

push

Evergreen

web-flow
Make async_open_realm() return StatusWith<std::shared_ptr<Realm>> (#7808)

This simplifies a lot of test code and eliminates some cases where the Realm
was being opened on a background thread, which is unsupported on linux.

102180 of 180376 branches covered (56.65%)

93 of 93 new or added lines in 4 files covered. (100.0%)

95 existing lines in 18 files now uncovered.

214765 of 236085 relevant lines covered (90.97%)

5528167.33 hits per line

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

75.82
/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_collections_mixed.cpp",
132
    "test_transform.cpp",
133
    "test_array.cpp",
134
    "test_lang_bind_helper_sync.cpp",
135
    "test_sync.cpp",
136
    "test_backup.cpp",
137
    "test_sync_fuzz.cpp"
138
};
139
// clang-format on
140

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

159

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

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

203
void set_always_encrypt()
204
{
8✔
205
    if (const char* env = getenv("UNITTEST_ENCRYPT_ALL")) {
8✔
206
        std::string str(env);
8✔
207
        for (auto& c : str) {
8✔
208
            c = tolower(c);
8✔
209
        }
8✔
210
        if (str == "1" || str == "on" || str == "yes") {
8✔
211
            enable_always_encrypt();
×
212
        }
×
213
    }
8✔
214
}
8✔
215

216
void display_build_config()
217
{
8✔
218
    const char* with_debug = Version::has_feature(feature_Debug) ? "Enabled" : "Disabled";
8✔
219

220
#if REALM_ENABLE_MEMDEBUG
221
    const char* memdebug = "Enabled";
222
#else
223
    const char* memdebug = "Disabled";
8✔
224
#endif
8✔
225

226
#if REALM_ENABLE_ENCRYPTION
8✔
227
    bool always_encrypt = is_always_encrypt_enabled();
8✔
228
    const char* encryption = always_encrypt ? "Enabled at compile-time (always encrypt = yes)"
8✔
229
                                            : "Enabled at compile-time (always encrypt = no)";
8✔
230
#else
231
    const char* encryption = "Disabled at compile-time";
232
#endif
233

234
#ifdef REALM_COMPILER_SSE
4✔
235
    const char* compiler_sse = "Yes";
4✔
236
#else
237
    const char* compiler_sse = "No";
4✔
238
#endif
4✔
239

240
#ifdef REALM_COMPILER_AVX
4✔
241
    const char* compiler_avx = "Yes";
4✔
242
#else
243
    const char* compiler_avx = "No";
4✔
244
#endif
4✔
245

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

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

250
    std::cout << std::endl
8✔
251
              << "Realm version: " << Version::get_version() << " with Debug " << with_debug << "\n"
8✔
252
              << "Platform: " << util::get_platform_info() << "\n"
8✔
253
              << "Encryption: " << encryption << "\n"
8✔
254
              << "\n"
8✔
255
              << "REALM_MAX_BPNODE_SIZE = " << REALM_MAX_BPNODE_SIZE << "\n"
8✔
256
              << "REALM_MEMDEBUG = " << memdebug << "\n"
8✔
257
              << "\n"
8✔
258
              // Be aware that ps3/xbox have sizeof (void*) = 4 && sizeof (size_t) == 8
259
              // We decide to print size_t here
260
              << "sizeof (size_t) * 8 = " << (sizeof(size_t) * 8) << "\n"
8✔
261
              << "\n"
8✔
262
              << "Compiler supported SSE (auto detect):       " << compiler_sse << "\n"
8✔
263
              << "This CPU supports SSE (auto detect):        " << cpu_sse << "\n"
8✔
264
              << "Compiler supported AVX (auto detect):       " << compiler_avx << "\n"
8✔
265
              << "This CPU supports AVX (AVX1) (auto detect): " << cpu_avx << "\n"
8✔
266
              << "\n"
8✔
267
              << "UNITTEST_RANDOM_SEED:                       " << unit_test_random_seed << "\n"
8✔
268
              << "Test path prefix:                           " << test_util::get_test_path_prefix() << "\n"
8✔
269
              << "Test resource path:                         " << test_util::get_test_resource_path() << "\n"
8✔
270
              << std::endl;
8✔
271
}
8✔
272

273

274
// Records elapsed time for each test and shows a "Top 5" at the end.
275
class CustomReporter : public SimpleReporter {
276
public:
277
    explicit CustomReporter(bool report_progress)
278
        : SimpleReporter(report_progress)
4✔
279
    {
8✔
280
    }
8✔
281

282
    ~CustomReporter() noexcept {}
8✔
283

284
    void end(const TestContext& context, double elapsed_seconds) override
285
    {
8,410✔
286
        result r;
8,410✔
287
        r.test_index = context.test_index;
8,410✔
288
        r.recurrence_index = context.recurrence_index;
8,410✔
289
        r.elapsed_seconds = elapsed_seconds;
8,410✔
290
        m_results.push_back(r);
8,410✔
291
        SimpleReporter::end(context, elapsed_seconds);
8,410✔
292
    }
8,410✔
293

294
    void summary(const SharedContext& context, const Summary& results_summary) override
295
    {
8✔
296
        SimpleReporter::summary(context, results_summary);
8✔
297

298
        size_t max_n = 5;
8✔
299
        size_t n = std::min<size_t>(max_n, m_results.size());
8✔
300
        if (n < 2)
8✔
301
            return;
×
302

303
        partial_sort(m_results.begin(), m_results.begin() + n, m_results.end());
8✔
304
        std::vector<std::tuple<std::string, std::string>> rows;
8✔
305
        size_t name_col_width = 0, time_col_width = 0;
8✔
306
        for (size_t i = 0; i < n; ++i) {
48✔
307
            const result& r = m_results[i];
40✔
308
            const TestDetails& details = context.test_list.get_test_details(r.test_index);
40✔
309
            std::ostringstream out;
40✔
310
            out.imbue(std::locale::classic());
40✔
311
            out << details.test_name;
40✔
312
            if (context.num_recurrences > 1)
40✔
313
                out << '#' << (r.recurrence_index + 1);
×
314
            std::string name = out.str();
40✔
315
            std::string time = Timer::format(r.elapsed_seconds);
40✔
316
            rows.emplace_back(name, time);
40✔
317
            if (name.size() > name_col_width)
40✔
318
                name_col_width = name.size();
12✔
319
            if (time.size() > time_col_width)
40✔
320
                time_col_width = time.size();
12✔
321
        }
40✔
322

323
        name_col_width += 2;
8✔
324
        size_t full_width = name_col_width + time_col_width;
8✔
325
        std::cout.fill('-');
8✔
326
        std::cout << "\nTop " << n << " time usage:\n"
8✔
327
                  << std::setw(int(full_width)) << ""
8✔
328
                  << "\n";
8✔
329
        std::cout.fill(' ');
8✔
330
        for (const auto& row : rows) {
40✔
331
            std::cout << std::left << std::setw(int(name_col_width)) << std::get<0>(row) << std::right
40✔
332
                      << std::setw(int(time_col_width)) << std::get<1>(row) << "\n";
40✔
333
        }
40✔
334
    }
8✔
335

336
private:
337
    struct result {
338
        size_t test_index;
339
        int recurrence_index;
340
        double elapsed_seconds;
341
        bool operator<(const result& r) const
342
        {
9,806✔
343
            return elapsed_seconds > r.elapsed_seconds; // Descending order
9,806✔
344
        }
9,806✔
345
    };
346

347
    std::vector<result> m_results;
348
};
349

350

351
void put_time(std::ostream& out, const std::tm& tm, const char* format)
352
{
×
353
    const std::time_put<char>& facet = std::use_facet<std::time_put<char>>(out.getloc());
×
354
    facet.put(std::ostreambuf_iterator<char>(out), out, ' ', &tm, format, format + strlen(format));
×
355
}
×
356

357

358
bool run_tests(const std::shared_ptr<realm::util::Logger>& logger = nullptr)
359
{
8✔
360
    {
8✔
361
        const char* str = getenv("UNITTEST_KEEP_FILES");
8✔
362
        if (str && strlen(str) != 0)
8!
363
            keep_test_files();
×
364
    }
8✔
365
    const bool running_spawned_process = getenv("REALM_SPAWNED");
8✔
366

367
    TestList::Config config;
8✔
368
    config.logger = logger;
8✔
369

370
    // Log timestamps
371
    {
8✔
372
        const char* str = getenv("UNITTEST_LOG_TIMESTAMPS");
8✔
373
        if (str && std::strlen(str) != 0)
8!
374
            config.log_timestamps = true;
×
375
    }
8✔
376

377
    // Set number of threads
378
    {
8✔
379
        const char* str = getenv("UNITTEST_THREADS");
8✔
380
        if (str && strlen(str) != 0) {
8!
381
            std::istringstream in(str);
×
382
            in.imbue(std::locale::classic());
×
383
            in.flags(in.flags() & ~std::ios_base::skipws); // Do not accept white space
×
384
            in >> config.num_threads;
×
385
            bool bad = !in || in.get() != std::char_traits<char>::eof() || config.num_threads < 1;
×
386
            if (bad)
×
387
                throw std::runtime_error("Bad number of threads");
×
388
            if (config.num_threads > 1 && !running_spawned_process)
×
389
                std::cout << "Number of test threads: " << config.num_threads << "\n\n";
×
390
        }
×
391
        else {
8✔
392
            config.num_threads = std::thread::hardware_concurrency();
8✔
393
            if (!running_spawned_process) {
8✔
394
                std::cout << "Number of test threads: " << config.num_threads << " (default)\n";
8✔
395
                std::cout << "(Use UNITTEST_THREADS=1 to serialize testing) \n\n";
8✔
396
            }
8✔
397
        }
8✔
398
    }
8✔
399

400
    // Set number of repetitions
401
    {
8✔
402
        const char* str = getenv("UNITTEST_REPEAT");
8✔
403
        if (str && strlen(str) != 0) {
8!
404
            std::istringstream in(str);
×
405
            in.imbue(std::locale::classic());
×
406
            in.flags(in.flags() & ~std::ios_base::skipws); // Do not accept white space
×
407
            in >> config.num_repetitions;
×
408
            bool bad = !in || in.get() != std::char_traits<char>::eof() || config.num_repetitions < 0;
×
409
            if (bad)
×
410
                throw std::runtime_error("Bad number of repetitions");
×
411
        }
×
412
    }
8✔
413

414
    // Shuffle
415
    {
8✔
416
        const char* str = getenv("UNITTEST_SHUFFLE");
8✔
417
        if (config.num_threads > 1 || (str && strlen(str) != 0))
8!
418
            config.shuffle = true;
8✔
419
    }
8✔
420

421
    // Set up reporter
422
    util::File junit_file;
8✔
423
    util::File::Streambuf junit_streambuf(&junit_file);
8✔
424
    std::ostream junit_out(&junit_streambuf);
8✔
425
    std::vector<std::unique_ptr<Reporter>> reporters;
8✔
426
    {
8✔
427
        const char* str = getenv("UNITTEST_PROGRESS");
8✔
428
        bool report_progress = str && strlen(str) != 0;
8✔
429
        reporters.push_back(std::make_unique<CustomReporter>(report_progress));
8✔
430
    }
8✔
431
    if (const char* str = getenv("UNITTEST_XML"); str && strlen(str) != 0) {
8!
432
        std::cout << "Configuring jUnit reporter to store test results in " << str << std::endl;
×
433
        junit_file.open(str, util::File::mode_Write);
×
434
        const char* test_suite_name = getenv("UNITTEST_SUITE_NAME");
×
435
        if (!test_suite_name || !strlen(test_suite_name))
×
436
            test_suite_name = "realm-core-tests";
×
437
        reporters.push_back(create_junit_reporter(junit_out, test_suite_name));
×
438
    }
×
439
    else if (const char* str = getenv("UNITTEST_EVERGREEN_TEST_RESULTS"); str && strlen(str) != 0) {
8✔
440
        std::cout << "Configuring evergreen reporter to store test results in " << str << std::endl;
8✔
441
        reporters.push_back(create_evergreen_reporter(str));
8✔
442
    }
8✔
443
    auto reporter = create_combined_reporter(reporters);
8✔
444
    config.reporter = reporter.get();
8✔
445

446
    // Set up filter
447
    const char* filter_str = getenv("UNITTEST_FILTER");
8✔
448
    const char* test_only = get_test_only();
8✔
449
    if (test_only)
8✔
450
        filter_str = test_only;
×
451
    std::unique_ptr<Filter> filter;
8✔
452
    if (filter_str && strlen(filter_str) != 0)
8!
453
        filter = create_wildcard_filter(filter_str);
×
454
    config.filter = filter.get();
8✔
455

456
    // Set intra test log level threshold
457
    {
8✔
458
        const char* str = getenv("UNITTEST_LOG_LEVEL");
8✔
459
        if (str && strlen(str) != 0) {
8!
460
            std::istringstream in(str);
×
461
            in.imbue(std::locale::classic());
×
462
            in.flags(in.flags() & ~std::ios_base::skipws); // Do not accept white space
×
463
            in >> config.intra_test_log_level;
×
464
            bool bad = !in || in.get() != std::char_traits<char>::eof();
×
465
            if (bad)
×
466
                throw std::runtime_error("Bad intra test log level");
×
467
        }
×
468
    }
8✔
469

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

486
    // Enable abort on failure
487
    {
8✔
488
        const char* str = getenv("UNITTEST_ABORT_ON_FAILURE");
8✔
489
        if (str && strlen(str) != 0) {
8!
490
            config.abort_on_failure = true;
×
491
        }
×
492
    }
8✔
493

494
    // Run
495
    TestList& list = get_default_test_list();
8✔
496
    list.sort(PatternBasedFileOrder(file_order));
8✔
497
    bool success = list.run(config);
8✔
498

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

502
    std::cout << "\n";
8✔
503

504
    // The iOS Simulator has a separate set of kernel file caches from the parent
505
    // OS, and if the simulator is deleted immediately after running the tests
506
    // (as is done on CI), the writes never actually make it to disk without
507
    // an explicit F_FULLFSYNC.
508
    if (junit_file.is_attached()) {
8✔
509
        junit_out.flush();
×
510
        junit_file.sync();
×
511
    }
×
512

513
    return success;
8✔
514
}
8✔
515

516
} // anonymous namespace
517

518

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

527
    // Disable buffering on std::cout so that progress messages can be related to
528
    // error messages.
529
    std::cout.setf(std::ios::unitbuf);
8✔
530

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

542
    char* no_error_exitcode_str = getenv("UNITTEST_NO_ERROR_EXITCODE");
8✔
543
    bool no_error_exit_status = no_error_exitcode_str && strlen(no_error_exitcode_str) != 0;
8!
544

545
#ifdef WIN32
546
#if REALM_UWP
547
    std::string path =
548
        winrt::to_string(winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path());
549
    path += "\\TestAssets\\";
550
    set_test_resource_path(path);
551
    set_test_path_prefix(path);
552
#endif
553
#endif
554

555
    set_random_seed();
8✔
556
    set_always_encrypt();
8✔
557

558
    fix_max_open_files();
8✔
559

560
    if (!getenv("REALM_SPAWNED"))
8✔
561
        display_build_config();
8✔
562

563
    long num_open_files = get_num_open_files();
8✔
564

565
    bool success = run_tests(logger);
8✔
566

567
    if (num_open_files >= 0) {
8✔
568
        long num_open_files_2 = get_num_open_files();
4✔
569
        REALM_ASSERT(num_open_files_2 >= 0);
4✔
570
        if (num_open_files_2 > num_open_files) {
4✔
571
            long n = num_open_files_2 - num_open_files;
×
572
            // FIXME: This should be an error, but OpenSSL seems to open
573
            // files behind our back, and calling OPENSSL_cleanup() does not
574
            // seem to have any effect.
575
            std::cerr << "WARNING: " << n << " file descriptors were leaked\n";
×
576
            // success = false;
577
        }
×
578
    }
4✔
579

580
#ifdef _MSC_VER
581
    // We don't want spawned processes (see spawned_process.hpp to require user interaction).
582
    if (!getenv("REALM_SPAWNED"))
583
        getchar(); // wait for key
584
#endif
585

586
    return success || no_error_exit_status ? EXIT_SUCCESS : EXIT_FAILURE;
8!
587
}
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