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

realm / realm-core / 2213

10 Apr 2024 11:21PM UTC coverage: 91.792% (-0.8%) from 92.623%
2213

push

Evergreen

web-flow
Add missing availability checks for SecCopyErrorMessageString (#7577)

This requires iOS 11.3 and we currently target iOS 11.

94842 of 175770 branches covered (53.96%)

7 of 22 new or added lines in 2 files covered. (31.82%)

1861 existing lines in 82 files now uncovered.

242866 of 264583 relevant lines covered (91.79%)

5593111.45 hits per line

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

90.72
/test/object-store/util/sync/sync_test_utils.hpp
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
#pragma once
20

21
#include "util/event_loop.hpp"
22
#include "util/test_file.hpp"
23
#include "util/test_utils.hpp"
24

25
#include <realm/object-store/sync/app.hpp>
26
#include <realm/object-store/sync/generic_network_transport.hpp>
27
#include <realm/object-store/sync/impl/sync_file.hpp>
28
#include <realm/object-store/sync/impl/app_metadata.hpp>
29
#include <realm/object-store/sync/sync_session.hpp>
30
#include <realm/object-store/thread_safe_reference.hpp>
31
#include <realm/sync/network/http.hpp>
32
#include <realm/sync/socket_provider.hpp>
33
#include <realm/sync/network/default_socket.hpp>
34

35
#include <realm/util/functional.hpp>
36
#include <realm/util/function_ref.hpp>
37

38
#include <catch2/catch_test_macros.hpp>
39
#include <catch2/matchers/catch_matchers_templated.hpp>
40

41
#include <chrono>
42
#include <vector>
43

44
// disable the tests that rely on having baas available on the network
45
// but allow opt-in by building with REALM_ENABLE_AUTH_TESTS=1
46
#ifndef REALM_ENABLE_AUTH_TESTS
47
#define REALM_ENABLE_AUTH_TESTS 0
48
#endif
49

50
namespace realm {
51

52
void timed_wait_for(util::FunctionRef<bool()> condition,
53
                    std::chrono::milliseconds max_ms = std::chrono::milliseconds(5000));
54

55
void timed_sleeping_wait_for(util::FunctionRef<bool()> condition,
56
                             std::chrono::milliseconds max_ms = std::chrono::seconds(30),
57
                             std::chrono::milliseconds sleep_ms = std::chrono::milliseconds(1));
58

59
class ReturnsTrueWithinTimeLimit : public Catch::Matchers::MatcherGenericBase {
60
public:
61
    ReturnsTrueWithinTimeLimit(std::chrono::milliseconds max_ms = std::chrono::milliseconds(5000))
62
        : m_max_ms(max_ms)
63
    {
4✔
64
    }
4✔
65

66
    bool match(util::FunctionRef<bool()> condition) const;
67

68
    std::string describe() const override
UNCOV
69
    {
×
UNCOV
70
        return util::format("PredicateReturnsTrueAfter %1ms", m_max_ms.count());
×
UNCOV
71
    }
×
72

73
private:
74
    std::chrono::milliseconds m_max_ms;
75
};
76

77
template <typename T>
78
struct TimedFutureState : public util::AtomicRefCountBase {
79
    TimedFutureState(util::Promise<T>&& promise)
80
        : promise(std::move(promise))
81
    {
64✔
82
    }
64✔
83

84
    util::Promise<T> promise;
85
    std::mutex mutex;
86
    std::condition_variable cv;
87
    bool finished = false;
88
};
89

90
template <typename T>
91
util::Future<T> wait_for_future(util::Future<T>&& input, std::chrono::milliseconds max_ms = std::chrono::seconds(60))
92
{
64✔
93
    auto pf = util::make_promise_future<T>();
64✔
94
    auto shared_state = util::make_bind<TimedFutureState<T>>(std::move(pf.promise));
64✔
95
    const auto delay = TEST_TIMEOUT_EXTRA > 0 ? max_ms + std::chrono::seconds(TEST_TIMEOUT_EXTRA) : max_ms;
64✔
96

32✔
97
    std::move(input).get_async([shared_state](StatusOrStatusWith<T> value) {
64✔
98
        std::unique_lock lk(shared_state->mutex);
64✔
99
        // If the state has already expired, then just return without doing anything.
32✔
100
        if (std::exchange(shared_state->finished, true)) {
64✔
UNCOV
101
            return;
×
UNCOV
102
        }
×
103

32✔
104
        shared_state->promise.set_from_status_with(std::move(value));
64✔
105
        shared_state->cv.notify_one();
64✔
106
        lk.unlock();
64✔
107
    });
64✔
108

32✔
109
    std::unique_lock lk(shared_state->mutex);
64✔
110
    if (!shared_state->cv.wait_for(lk, delay, [&] {
116✔
111
            return shared_state->finished;
116✔
112
        })) {
58✔
UNCOV
113
        shared_state->finished = true;
×
UNCOV
114
        shared_state->promise.set_error(
×
UNCOV
115
            {ErrorCodes::RuntimeError, util::format("wait_for_future exceeded %1 ms", delay.count())});
×
116
    }
×
117

32✔
118
    return std::move(pf.future);
64✔
119
}
64✔
120

121
struct ExpectedRealmPaths {
122
    ExpectedRealmPaths(const std::string& base_path, const std::string& app_id, const std::string& user_identity,
123
                       const std::vector<std::string>& legacy_identities, const std::string& partition);
124
    std::string current_preferred_path;
125
    std::string fallback_hashed_path;
126
    std::string legacy_local_id_path;
127
    std::string legacy_sync_path;
128
    std::vector<std::string> legacy_sync_directories_to_make;
129
};
130

131
// Takes a string_view of a possibly quoted string (i.e. the string begins with '"' and ends with '"')
132
// and returns an owned string without the quotes.
133
std::string unquote_string(std::string_view possibly_quoted_string);
134

135
#if REALM_ENABLE_SYNC
136

137
template <typename Transport>
138
const std::shared_ptr<app::GenericNetworkTransport> instance_of = std::make_shared<Transport>();
139

140
std::ostream& operator<<(std::ostream& os, util::Optional<app::AppError> error);
141

142
void subscribe_to_all_and_bootstrap(Realm& realm);
143

144
struct AutoVerifiedEmailCredentials : app::AppCredentials {
145
    AutoVerifiedEmailCredentials();
146
    std::string email;
147
    std::string password;
148
};
149

150
AutoVerifiedEmailCredentials create_user_and_log_in(app::SharedApp app);
151
// Log in the user again using the AutoVerifiedEmailCredentials returned
152
// when calling create_user_and_log_in()
153
void log_in_user(app::SharedApp app, app::AppCredentials creds);
154

155
#if REALM_ENABLE_AUTH_TESTS
156
void wait_for_sessions_to_close(const TestAppSession& test_app_session);
157

158
std::string get_compile_time_base_url();
159
std::string get_compile_time_admin_url();
160
#endif // REALM_ENABLE_AUTH_TESTS
161

162
void wait_for_advance(Realm& realm);
163

164
void async_open_realm(const Realm::Config& config,
165
                      util::UniqueFunction<void(ThreadSafeReference&& ref, std::exception_ptr e)> finish);
166

167
app::Response do_http_request(const app::Request& request);
168

169
class SynchronousTestTransport : public app::GenericNetworkTransport {
170
public:
171
    void send_request_to_server(const app::Request& request,
172
                                util::UniqueFunction<void(const app::Response&)>&& completion) override
173
    {
4,325✔
174
        {
4,325✔
175
            std::lock_guard barrier(m_mutex);
4,325✔
176
        }
4,325✔
177
        completion(do_http_request(request));
4,325✔
178
    }
4,325✔
179

180
    void block()
181
    {
6✔
182
        m_mutex.lock();
6✔
183
    }
6✔
184
    void unblock()
185
    {
6✔
186
        m_mutex.unlock();
6✔
187
    }
6✔
188

189
private:
190
    std::mutex m_mutex;
191
};
192

193
template <typename BaseTransport = SynchronousTestTransport>
194
class HookedTransport : public BaseTransport {
195
    static_assert(std::is_base_of_v<app::GenericNetworkTransport, BaseTransport>);
196

197
public:
198
    void send_request_to_server(const app::Request& request,
199
                                util::UniqueFunction<void(const app::Response&)>&& completion) override
200
    {
208✔
201
        if (request_hook) {
208✔
202
            if (auto simulated_response = request_hook(request)) {
158✔
203
                return completion(*simulated_response);
112✔
204
            }
112✔
205
        }
96✔
206
        BaseTransport::send_request_to_server(request, [&](app::Response response) mutable {
96✔
207
            if (response_hook) {
96✔
208
                response_hook(request, response);
14✔
209
            }
14✔
210
            completion(response);
96✔
211
        });
96✔
212
    }
96✔
213

214
    // Optional handler for the request and response before it is returned to completion
215
    util::UniqueFunction<void(const app::Request&, app::Response&)> response_hook;
216
    // Optional handler for the request before it is sent to the server
217
    util::UniqueFunction<std::optional<app::Response>(const app::Request&)> request_hook;
218
};
219

220

221
struct SocketProviderError {
222
    SocketProviderError(sync::HTTPStatus code, std::string message = "")
223
        : SocketProviderError(static_cast<int>(code), message)
224
    {
6✔
225
    }
6✔
226

227
    SocketProviderError(int code, std::string message = "")
228
        : status_code(code)
229
        , was_clean(code == 101)
230
        , body(message)
231
    {
6✔
232
    }
6✔
233

234
    using WebSocketError = sync::websocket::WebSocketError;
235
    SocketProviderError(WebSocketError error, std::string message = "")
236
        : was_clean(false)
237
        , ws_error(error)
238
        , body(message)
239
    {
40✔
240
    }
40✔
241

242
    int status_code = 0;
243
    bool was_clean = true;
244
    WebSocketError ws_error = WebSocketError::websocket_ok;
245
    std::string body;
246
};
247

248

249
struct HookedSocketProvider : public sync::websocket::DefaultSocketProvider {
250
    HookedSocketProvider(const std::shared_ptr<util::Logger>& logger, const std::string& user_agent,
251
                         AutoStart auto_start = AutoStart{true})
252
        : DefaultSocketProvider(logger, user_agent, nullptr, auto_start)
253
    {
26✔
254
    }
26✔
255

256
    std::unique_ptr<sync::WebSocketInterface> connect(std::unique_ptr<sync::WebSocketObserver> observer,
257
                                                      sync::WebSocketEndpoint&& endpoint) override
258
    {
54✔
259
        std::optional<SocketProviderError> error;
54✔
260
        if (endpoint_verify_func) {
54✔
261
            endpoint_verify_func(endpoint);
40✔
262
        }
40✔
263

27✔
264
        if (websocket_endpoint_resolver) {
54✔
265
            websocket_endpoint_resolver(endpoint);
14✔
266
        }
14✔
267

27✔
268
        if (websocket_connect_func) {
54✔
269
            error = websocket_connect_func();
48✔
270
        }
48✔
271

27✔
272
        if (error && error->ws_error != sync::websocket::WebSocketError::websocket_ok) {
54✔
273
            observer->websocket_error_handler();
40✔
274
            observer->websocket_closed_handler(error->was_clean, error->ws_error, error->body);
40✔
275
            return nullptr;
40✔
276
        }
40✔
277

7✔
278
        std::unique_ptr<sync::WebSocketInterface> websocket =
14✔
279
            DefaultSocketProvider::connect(std::move(observer), std::move(endpoint));
14✔
280
        if (error && error->status_code > 0) {
14✔
281
            auto default_websocket = dynamic_cast<sync::websocket::DefaultWebSocket*>(websocket.get());
6✔
282
            if (default_websocket)
6✔
283
                default_websocket->force_handshake_response_for_testing(error->status_code, error->body);
6✔
284
        }
6✔
285
        return websocket;
14✔
286
    }
14✔
287

288
    util::UniqueFunction<void(sync::WebSocketEndpoint&)> websocket_endpoint_resolver;
289
    util::UniqueFunction<void(const sync::WebSocketEndpoint&)> endpoint_verify_func;
290
    util::UniqueFunction<std::optional<SocketProviderError>()> websocket_connect_func;
291
};
292

293
#endif // REALM_ENABLE_SYNC
294

295
namespace reset_utils {
296

297
struct Partition {
298
    std::string property_name;
299
    std::string value;
300
};
301

302
Obj create_object(Realm& realm, StringData object_type, util::Optional<ObjectId> primary_key = util::none,
303
                  util::Optional<Partition> partition = util::none);
304

305
struct TestClientReset {
306
    using Callback = util::UniqueFunction<void(const SharedRealm&)>;
307
    using InitialObjectCallback = util::UniqueFunction<ObjectId(const SharedRealm&)>;
308
    TestClientReset(const Realm::Config& local_config, const Realm::Config& remote_config);
309
    virtual ~TestClientReset();
310
    TestClientReset* setup(Callback&& on_setup);
311

312
    // Only used in FLX sync client reset tests.
313
    TestClientReset* populate_initial_object(InitialObjectCallback&& callback);
314
    TestClientReset* make_local_changes(Callback&& changes_local);
315
    TestClientReset* make_remote_changes(Callback&& changes_remote);
316
    TestClientReset* on_post_local_changes(Callback&& post_local);
317
    TestClientReset* on_post_reset(Callback&& post_reset);
318
    void set_pk_of_object_driving_reset(const ObjectId& pk);
319
    ObjectId get_pk_of_object_driving_reset() const;
320
    void disable_wait_for_reset_completion();
321

322
    virtual TestClientReset* set_development_mode(bool enable = true);
323
    virtual void run() = 0;
324

325
protected:
326
    realm::Realm::Config m_local_config;
327
    realm::Realm::Config m_remote_config;
328

329
    Callback m_on_setup;
330
    InitialObjectCallback m_populate_initial_object;
331
    Callback m_make_local_changes;
332
    Callback m_make_remote_changes;
333
    Callback m_on_post_local;
334
    Callback m_on_post_reset;
335
    bool m_did_run = false;
336
    ObjectId m_pk_driving_reset = ObjectId::gen();
337
    bool m_wait_for_reset_completion = true;
338
};
339

340
#if REALM_ENABLE_SYNC
341

342
#if REALM_ENABLE_AUTH_TESTS
343
std::unique_ptr<TestClientReset> make_baas_client_reset(const Realm::Config& local_config,
344
                                                        const Realm::Config& remote_config,
345
                                                        TestAppSession& test_app_session);
346

347
std::unique_ptr<TestClientReset> make_baas_flx_client_reset(const Realm::Config& local_config,
348
                                                            const Realm::Config& remote_config,
349
                                                            const TestAppSession& test_app_session);
350

351
void wait_for_object_to_persist_to_atlas(std::shared_ptr<app::User> user, const AppSession& app_session,
352
                                         const std::string& schema_name, const bson::BsonDocument& filter_bson);
353

354
void wait_for_num_objects_in_atlas(std::shared_ptr<app::User> user, const AppSession& app_session,
355
                                   const std::string& schema_name, size_t expected_size);
356

357
void trigger_client_reset(const AppSession& app_session, const SyncSession& sync_session);
358
void trigger_client_reset(const AppSession& app_session, const SharedRealm& realm);
359
#endif // REALM_ENABLE_AUTH_TESTS
360

361
#endif // REALM_ENABLE_SYNC
362

363
std::unique_ptr<TestClientReset> make_fake_local_client_reset(const Realm::Config& local_config,
364
                                                              const Realm::Config& remote_config);
365

366
} // namespace reset_utils
367

368
} // namespace realm
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