From 60d6c3372486aec57ffbdec5dd7c667c75e7f361 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Wed, 14 Feb 2024 12:00:35 -0800 Subject: [PATCH] Simplify session tests by consitently using TestSyncManager::fake_user() --- test/object-store/audit.cpp | 6 +- test/object-store/sync/app.cpp | 28 ++-- test/object-store/sync/client_reset.cpp | 6 +- .../connection_change_notifications.cpp | 30 +--- test/object-store/sync/session/session.cpp | 149 ++++++++---------- .../sync/session/wait_for_completion.cpp | 45 ++---- test/object-store/sync/sync_manager.cpp | 50 +++--- test/object-store/sync/user.cpp | 14 +- .../util/sync/sync_test_utils.cpp | 4 +- test/object-store/util/test_file.hpp | 8 + 10 files changed, 141 insertions(+), 199 deletions(-) diff --git a/test/object-store/audit.cpp b/test/object-store/audit.cpp index 3be735c95da..7d04d0c4690 100644 --- a/test/object-store/audit.cpp +++ b/test/object-store/audit.cpp @@ -78,7 +78,7 @@ util::Optional to_optional_string(StringData sd) std::vector get_audit_events(TestSyncManager& manager, bool parse_events = true) { // Wait for all sessions to be fully uploaded and then tear them down - auto sync_manager = manager.app()->sync_manager(); + auto sync_manager = manager.sync_manager(); REALM_ASSERT(sync_manager); auto sessions = sync_manager->get_all_sessions(); for (auto& session : sessions) { @@ -1572,7 +1572,7 @@ TEST_CASE("audit realm sharding", "[sync][pbs][audit]") { auto close_all_sessions = [&] { realm->close(); realm = nullptr; - auto sync_manager = test_session.app()->sync_manager(); + auto sync_manager = test_session.sync_manager(); for (auto& session : sync_manager->get_all_sessions()) { session->shutdown_and_wait(); } @@ -1785,7 +1785,7 @@ TEST_CASE("audit integration tests", "[sync][pbs][audit][baas]") { auto audit_user = session.app()->current_user(); config.audit_config->audit_user = audit_user; auto realm = Realm::get_shared_realm(config); - session.app()->sync_manager()->remove_user(audit_user->identity()); + session.sync_manager()->remove_user(audit_user->identity()); auto audit = realm->audit_context(); auto scope = audit->begin_scope("scope"); diff --git a/test/object-store/sync/app.cpp b/test/object-store/sync/app.cpp index 29d8b64fb1d..441351f82c2 100644 --- a/test/object-store/sync/app.cpp +++ b/test/object-store/sync/app.cpp @@ -3083,7 +3083,7 @@ TEST_CASE("app: sync integration", "[sync][pbs][app][baas]") { REQUIRE(!wait_for_download(*r)); SECTION("Valid websocket redirect") { - auto sync_manager = test_session.app()->sync_manager(); + auto sync_manager = test_session.sync_manager(); auto sync_session = sync_manager->get_existing_session(r->config().path); sync_session->pause(); @@ -3150,7 +3150,7 @@ TEST_CASE("app: sync integration", "[sync][pbs][app][baas]") { REQUIRE((server_url && server_url->find(redirect_host) != std::string::npos)); } SECTION("Websocket redirect logs out user") { - auto sync_manager = test_session.app()->sync_manager(); + auto sync_manager = test_session.sync_manager(); auto sync_session = sync_manager->get_existing_session(r->config().path); sync_session->pause(); @@ -3204,7 +3204,7 @@ TEST_CASE("app: sync integration", "[sync][pbs][app][baas]") { REQUIRE(!user1->is_logged_in()); } SECTION("Too many websocket redirects logs out user") { - auto sync_manager = test_session.app()->sync_manager(); + auto sync_manager = test_session.sync_manager(); auto sync_session = sync_manager->get_existing_session(r->config().path); sync_session->pause(); @@ -4846,8 +4846,7 @@ TEST_CASE("app: UserAPIKeyProviderClient unit_tests", "[sync][app][user][api key auto app = sync_manager.app(); auto client = app->provider_client(); - std::shared_ptr logged_in_user = - app->sync_manager()->get_user("userid", good_access_token, good_access_token, dummy_device_id); + auto logged_in_user = sync_manager.fake_user(); bool processed = false; ObjectId obj_id(UnitTestTransport::api_key_id.c_str()); @@ -5379,13 +5378,6 @@ TEST_CASE("app: auth providers", "[sync][app][user]") { } TEST_CASE("app: refresh access token unit tests", "[sync][app][user][token]") { - auto setup_user = [](std::shared_ptr app) { - if (app->sync_manager()->get_current_user()) { - return; - } - app->sync_manager()->get_user("a_user_id", good_access_token, good_access_token, dummy_device_id); - }; - SECTION("refresh custom data happy path") { static bool session_route_hit = false; @@ -5406,10 +5398,10 @@ TEST_CASE("app: refresh access token unit tests", "[sync][app][user][token]") { TestSyncManager sync_manager(get_config(instance_of)); auto app = sync_manager.app(); - setup_user(app); + auto user = sync_manager.fake_user(); bool processed = false; - app->refresh_custom_data(app->sync_manager()->get_current_user(), [&](const Optional& error) { + app->refresh_custom_data(user, [&](const Optional& error) { REQUIRE_FALSE(error); CHECK(session_route_hit); processed = true; @@ -5437,10 +5429,10 @@ TEST_CASE("app: refresh access token unit tests", "[sync][app][user][token]") { TestSyncManager sync_manager(get_config(instance_of)); auto app = sync_manager.app(); - setup_user(app); + auto user = sync_manager.fake_user(); bool processed = false; - app->refresh_custom_data(app->sync_manager()->get_current_user(), [&](const Optional& error) { + app->refresh_custom_data(user, [&](const Optional& error) { CHECK(error->reason() == "malformed JWT"); CHECK(error->code() == ErrorCodes::BadToken); CHECK(session_route_hit); @@ -5515,9 +5507,7 @@ TEST_CASE("app: refresh access token unit tests", "[sync][app][user][token]") { }; TestSyncManager sync_manager(get_config(instance_of)); - auto app = sync_manager.app(); - setup_user(app); - REQUIRE(log_in(app)); + REQUIRE(log_in(sync_manager.app())); } } diff --git a/test/object-store/sync/client_reset.cpp b/test/object-store/sync/client_reset.cpp index 914585ead7e..a36c91059d1 100644 --- a/test/object-store/sync/client_reset.cpp +++ b/test/object-store/sync/client_reset.cpp @@ -326,7 +326,7 @@ TEST_CASE("sync: client reset", "[sync][pbs][client reset][baas]") { recovery_path = recovery_path_it->second; REQUIRE(util::File::exists(orig_path)); REQUIRE(!util::File::exists(recovery_path)); - bool did_reset_files = test_app_session.app()->sync_manager()->immediately_run_file_actions(orig_path); + bool did_reset_files = test_app_session.sync_manager()->immediately_run_file_actions(orig_path); REQUIRE(did_reset_files); REQUIRE(!util::File::exists(orig_path)); REQUIRE(util::File::exists(recovery_path)); @@ -953,7 +953,7 @@ TEST_CASE("sync: client reset", "[sync][pbs][client reset][baas]") { auto realm = Realm::get_shared_realm(temp_config); wait_for_upload(*realm); - session = test_app_session.app()->sync_manager()->get_existing_session(temp_config.path); + session = test_app_session.sync_manager()->get_existing_session(temp_config.path); REQUIRE(session); } sync::SessionErrorInfo synthetic(Status{ErrorCodes::SyncClientResetRequired, "A fake client reset error"}, @@ -1005,7 +1005,7 @@ TEST_CASE("sync: client reset", "[sync][pbs][client reset][baas]") { }, std::chrono::seconds(20)); } - auto session = test_app_session.app()->sync_manager()->get_existing_session(local_config.path); + auto session = test_app_session.sync_manager()->get_existing_session(local_config.path); if (session) { session->shutdown_and_wait(); } diff --git a/test/object-store/sync/session/connection_change_notifications.cpp b/test/object-store/sync/session/connection_change_notifications.cpp index aabfb812494..5f182c65d97 100644 --- a/test/object-store/sync/session/connection_change_notifications.cpp +++ b/test/object-store/sync/session/connection_change_notifications.cpp @@ -20,41 +20,15 @@ #include #include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#ifndef _WIN32 -#include -#endif - using namespace realm; using namespace realm::util; -static const std::string dummy_device_id = "123400000000000000000000"; - -static const std::string base_path = util::make_temp_dir() + "realm_objectstore_sync_connection_state_changes"; - TEST_CASE("sync: Connection state changes", "[sync][session][connection change]") { if (!EventLoop::has_implementation()) return; - TestSyncManager::Config config; - config.base_path = base_path; - TestSyncManager init_sync_manager(config); - auto app = init_sync_manager.app(); - auto user = app->sync_manager()->get_user("user", ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("also_not_a_real_token"), dummy_device_id); + TestSyncManager tsm; + auto user = tsm.fake_user(); SECTION("register connection change listener") { auto session = sync_session( diff --git a/test/object-store/sync/session/session.cpp b/test/object-store/sync/session/session.cpp index 1530a6744ce..3d2107ebb18 100644 --- a/test/object-store/sync/session/session.cpp +++ b/test/object-store/sync/session/session.cpp @@ -41,25 +41,26 @@ using namespace realm; using namespace realm::util; -static const std::string dummy_device_id = "123400000000000000000000"; - -static std::shared_ptr get_user(const std::shared_ptr& app) -{ - return app->sync_manager()->get_user("user_id", ENCODE_FAKE_JWT("fake_refresh_token"), - ENCODE_FAKE_JWT("fake_access_token"), dummy_device_id); -} - TEST_CASE("SyncSession: management by SyncUser", "[sync][session]") { if (!EventLoop::has_implementation()) return; - TestSyncManager init_sync_manager; - auto& server = init_sync_manager.sync_server(); - auto app = init_sync_manager.app(); + using State = SyncUser::State; + + TestSyncManager tsm; + auto& server = tsm.sync_server(); const std::string realm_base_url = server.base_url(); + auto check_for_sessions = [](SyncUser& user, size_t count, SyncSession::State state) { + auto sessions = user.all_sessions(); + CHECK(sessions.size() == count); + for (auto& session : sessions) { + CHECK(session->state() == state); + } + }; + SECTION("a SyncUser can properly retrieve its owned sessions") { - auto user = get_user(app); + auto user = tsm.fake_user(); auto session1 = sync_session(user, "/test1a-1"); auto session2 = sync_session(user, "/test1a-2"); EventLoop::main().run_until([&] { @@ -67,7 +68,7 @@ TEST_CASE("SyncSession: management by SyncUser", "[sync][session]") { }); // Check the sessions on the SyncUser. - REQUIRE(user->all_sessions().size() == 2); + check_for_sessions(*user, 2, SyncSession::State::Active); auto s1 = user->session_for_on_disk_path(session1->path()); REQUIRE(s1 == session1); auto s2 = user->session_for_on_disk_path(session2->path()); @@ -75,64 +76,60 @@ TEST_CASE("SyncSession: management by SyncUser", "[sync][session]") { } SECTION("a SyncUser properly unbinds its sessions upon logging out") { - auto user = get_user(app); + auto user = tsm.fake_user(); auto session1 = sync_session(user, "/test1b-1"); auto session2 = sync_session(user, "/test1b-2"); EventLoop::main().run_until([&] { return sessions_are_active(*session1, *session2); }); - // Log the user out. user->log_out(); // The sessions should log themselves out. EventLoop::main().run_until([&] { return sessions_are_inactive(*session1, *session2); }); - CHECK(user->all_sessions().size() == 0); + check_for_sessions(*user, 0, SyncSession::State::Inactive); } SECTION("a SyncUser defers binding new sessions until it is logged in") { - auto user = get_user(app); + auto user = tsm.fake_user(); user->log_out(); - REQUIRE(user->state() == SyncUser::State::LoggedOut); + REQUIRE(user->state() == State::LoggedOut); auto session1 = sync_session(user, "/test1c-1"); auto session2 = sync_session(user, "/test1c-2"); // Run the runloop many iterations to see if the sessions spuriously bind. spin_runloop(); REQUIRE(session1->state() == SyncSession::State::Inactive); REQUIRE(session2->state() == SyncSession::State::Inactive); - REQUIRE(user->all_sessions().size() == 0); - // Log the user back in via the sync manager. - user = get_user(app); + check_for_sessions(*user, 0, SyncSession::State::Inactive); + user->log_in(ENCODE_FAKE_JWT("fake_access_token"), ENCODE_FAKE_JWT("fake_refresh_token")); EventLoop::main().run_until([&] { return sessions_are_active(*session1, *session2); }); - REQUIRE(user->all_sessions().size() == 2); + check_for_sessions(*user, 2, SyncSession::State::Active); } SECTION("a SyncUser properly rebinds existing sessions upon logging back in") { - auto user = get_user(app); + auto user = tsm.fake_user(); auto session1 = sync_session(user, "/test1d-1"); auto session2 = sync_session(user, "/test1d-2"); // Make sure the sessions are bound. EventLoop::main().run_until([&] { return sessions_are_active(*session1, *session2); }); - REQUIRE(user->all_sessions().size() == 2); - // Log the user out. + check_for_sessions(*user, 2, SyncSession::State::Active); user->log_out(); - REQUIRE(user->state() == SyncUser::State::LoggedOut); + REQUIRE(user->state() == State::LoggedOut); // Run the runloop many iterations to see if the sessions spuriously rebind. spin_runloop(); REQUIRE(session1->state() == SyncSession::State::Inactive); REQUIRE(session2->state() == SyncSession::State::Inactive); - REQUIRE(user->all_sessions().size() == 0); - // Log the user back in via the sync manager. - user = get_user(app); + check_for_sessions(*user, 0, SyncSession::State::Inactive); + user->log_in(ENCODE_FAKE_JWT("fake_access_token"), ENCODE_FAKE_JWT("fake_refresh_token")); EventLoop::main().run_until([&] { return sessions_are_active(*session1, *session2); }); - REQUIRE(user->all_sessions().size() == 2); + check_for_sessions(*user, 2, SyncSession::State::Active); } SECTION("sessions that were destroyed can be properly recreated when requested again") { @@ -140,7 +137,7 @@ TEST_CASE("SyncSession: management by SyncUser", "[sync][session]") { std::weak_ptr weak_session; std::string on_disk_path; util::Optional config; - auto user = get_user(app); + auto user = tsm.fake_user(); { // Create the session within a nested scope, so we can control its lifetime. auto session = sync_session( @@ -166,7 +163,7 @@ TEST_CASE("SyncSession: management by SyncUser", "[sync][session]") { } SECTION("a user can create multiple sessions for the same URL") { - auto user = get_user(app); + auto user = tsm.fake_user(); // Note that this should put the sessions at different paths. auto session1 = sync_session(user, "/test"); auto session2 = sync_session(user, "/test"); @@ -180,9 +177,8 @@ TEST_CASE("sync: log-in", "[sync][session]") { return; // Disable file-related functionality and metadata functionality for testing purposes. - TestSyncManager init_sync_manager; - auto app = init_sync_manager.app(); - auto user = get_user(app); + TestSyncManager tsm; + auto user = tsm.fake_user(); SECTION("Can log in") { std::atomic error_count(0); @@ -200,14 +196,12 @@ TEST_CASE("sync: log-in", "[sync][session]") { CHECK(error_count == 0); } - // TODO: write a test that logs out a Realm with multiple sessions, then logs it back in? // TODO: write tests that check that a Session properly handles various types of errors reported via its callback. } TEST_CASE("SyncSession: close() API", "[sync][session]") { - TestSyncManager init_sync_manager; - auto app = init_sync_manager.app(); - auto user = get_user(app); + TestSyncManager tsm; + auto user = tsm.fake_user(); SECTION("Behaves properly when called on session in the 'active' or 'inactive' state") { auto session = sync_session(user, "/test-close-for-active"); @@ -233,9 +227,8 @@ TEST_CASE("SyncSession: close() API", "[sync][session]") { } TEST_CASE("SyncSession: pause()/resume() API", "[sync][session]") { - TestSyncManager init_sync_manager; - auto app = init_sync_manager.app(); - auto user = get_user(app); + TestSyncManager tsm; + auto user = tsm.fake_user(); auto session = sync_session(user, "/test-close-for-active"); EventLoop::main().run_until([&] { @@ -286,9 +279,8 @@ TEST_CASE("SyncSession: pause()/resume() API", "[sync][session]") { } TEST_CASE("SyncSession: shutdown_and_wait() API", "[sync][session]") { - TestSyncManager init_sync_manager; - auto app = init_sync_manager.app(); - auto user = get_user(app); + TestSyncManager tsm; + auto user = tsm.fake_user(); SECTION("Behaves properly when called on session in the 'active' or 'inactive' state") { auto session = sync_session(user, "/test-close-for-active"); @@ -309,10 +301,8 @@ TEST_CASE("SyncSession: shutdown_and_wait() API", "[sync][session]") { } TEST_CASE("SyncSession: internal pause_async API", "[sync][session]") { - TestSyncManager init_sync_manager; - auto app = init_sync_manager.app(); - auto user = app->sync_manager()->get_user("close-api-tests-user", ENCODE_FAKE_JWT("fake_refresh_token"), - ENCODE_FAKE_JWT("fake_access_token"), dummy_device_id); + TestSyncManager tsm; + auto user = tsm.fake_user("close-api-tests-user"); auto session = sync_session( user, "/test-close-for-active", [](auto, auto) {}, SyncSessionStopPolicy::AfterChangesUploaded); @@ -332,9 +322,8 @@ TEST_CASE("SyncSession: internal pause_async API", "[sync][session]") { } TEST_CASE("SyncSession: update_configuration()", "[sync][session]") { - TestSyncManager init_sync_manager({}, {false}); - auto app = init_sync_manager.app(); - auto user = get_user(app); + TestSyncManager tsm({}, {false}); + auto user = tsm.fake_user(); auto session = sync_session(user, "/update_configuration"); SECTION("updates reported configuration") { @@ -366,8 +355,7 @@ TEST_CASE("SyncSession: update_configuration()", "[sync][session]") { } TEST_CASE("sync: error handling", "[sync][session]") { - TestSyncManager init_sync_manager; - auto app = init_sync_manager.app(); + TestSyncManager tsm; std::string on_disk_path; std::optional error; @@ -378,9 +366,9 @@ TEST_CASE("sync: error handling", "[sync][session]") { }; SECTION("reports DNS error") { - app->sync_manager()->set_sync_route("ws://invalid.com:9090"); + tsm.sync_manager()->set_sync_route("ws://invalid.com:9090"); - auto user = get_user(app); + auto user = tsm.fake_user(); auto session = sync_session(user, "/test", store_sync_error); timed_wait_for( [&] { @@ -398,14 +386,14 @@ TEST_CASE("sync: error handling", "[sync][session]") { #if !(defined(SWIFT_PACKAGE) || REALM_MOBILE) SECTION("reports TLS error as handshake failed") { TestSyncManager ssl_sync_manager({}, {StartImmediately{true}, EnableSSL{true}}); - auto app = ssl_sync_manager.app(); - - auto user = get_user(app); + auto user = ssl_sync_manager.fake_user(); auto session = sync_session(user, "/test", store_sync_error); - timed_wait_for([&] { - std::lock_guard lock(mutex); - return error.has_value(); - }); + timed_wait_for( + [&] { + std::lock_guard lock(mutex); + return error.has_value(); + }, + std::chrono::seconds(35)); REQUIRE(error); CHECK(error->status.code() == ErrorCodes::TlsHandshakeFailed); #if REALM_HAVE_SECURE_TRANSPORT @@ -423,7 +411,7 @@ TEST_CASE("sync: error handling", "[sync][session]") { using ProtocolErrorInfo = realm::sync::ProtocolErrorInfo; SECTION("Doesn't treat unknown system errors as being fatal") { - auto user = get_user(app); + auto user = tsm.fake_user(); auto session = sync_session(user, "/test", store_sync_error); EventLoop::main().run_until([&] { return sessions_are_active(*session); @@ -439,7 +427,8 @@ TEST_CASE("sync: error handling", "[sync][session]") { } SECTION("Properly handles a client reset error") { - auto user = get_user(app); + auto user = tsm.fake_user(); + auto session = sync_session(user, "/test", store_sync_error); std::string on_disk_path = session->path(); EventLoop::main().run_until([&] { @@ -467,7 +456,9 @@ TEST_CASE("sync: error handling", "[sync][session]") { std::string recovery_path = error->user_info[SyncError::c_recovery_file_path_key]; auto idx = recovery_path.find("recovered_realm"); CHECK(idx != std::string::npos); - idx = recovery_path.find(app->sync_manager()->recovery_directory_path()); + idx = recovery_path.find(tsm.sync_manager()->recovery_directory_path()); + CHECK(idx != std::string::npos); + idx = recovery_path.find(tsm.app()->config().app_id); CHECK(idx != std::string::npos); if (just_before.tm_year == just_after.tm_year) { idx = recovery_path.find(util::format_local_time(just_after_raw, "%Y")); @@ -489,9 +480,9 @@ TEST_CASE("sync: stop policy behavior", "[sync][session]") { return; // Server is initially stopped so we can control when the session exits the dying state. - TestSyncManager init_sync_manager({}, {false}); - auto& server = init_sync_manager.sync_server(); - auto sync_manager = init_sync_manager.app()->sync_manager(); + TestSyncManager tsm({}, {false}); + auto& server = tsm.sync_server(); + auto sync_manager = tsm.sync_manager(); auto schema = Schema{ {"object", { @@ -502,7 +493,7 @@ TEST_CASE("sync: stop policy behavior", "[sync][session]") { std::atomic error_handler_invoked(false); Realm::Config config; - auto user = get_user(init_sync_manager.app()); + auto user = tsm.fake_user(); auto create_session = [&](SyncSessionStopPolicy stop_policy) { auto session = sync_session( @@ -595,9 +586,8 @@ TEST_CASE("session restart", "[sync][session]") { if (!EventLoop::has_implementation()) return; - TestSyncManager init_sync_manager({}, {false}); - auto& server = init_sync_manager.sync_server(); - auto app = init_sync_manager.app(); + TestSyncManager tsm({}, {false}); + auto& server = tsm.sync_server(); Realm::Config config; auto schema = Schema{ {"object", @@ -607,7 +597,7 @@ TEST_CASE("session restart", "[sync][session]") { }}, }; - auto user = get_user(app); + auto user = tsm.fake_user(); auto session = sync_session( user, "/test-restart", [&](auto, auto) {}, SyncSessionStopPolicy::AfterChangesUploaded, nullptr, schema, &config); @@ -638,11 +628,12 @@ TEST_CASE("sync: non-synced metadata table doesn't result in non-additive schema return; // Disable file-related functionality and metadata functionality for testing purposes. - TestSyncManager init_sync_manager; - + TestSyncManager tsm; + auto user = tsm.fake_user(); + ; // Create a synced Realm containing a class with two properties. { - SyncTestFile config1(init_sync_manager.app(), "schema-version-test"); + SyncTestFile config1(user, "schema-version-test"); config1.schema_version = 1; config1.schema = Schema{ {"object", @@ -657,7 +648,7 @@ TEST_CASE("sync: non-synced metadata table doesn't result in non-additive schema // Download the existing Realm into a second local file without specifying a schema, // mirroring how `openAsync` works. - SyncTestFile config2(init_sync_manager.app(), "schema-version-test"); + SyncTestFile config2(user, "schema-version-test"); config2.schema_version = 1; { auto realm2 = Realm::get_shared_realm(config2); @@ -668,7 +659,7 @@ TEST_CASE("sync: non-synced metadata table doesn't result in non-additive schema // only a single property. This should not result in us trying to remove `property2`, // and will throw an exception if it does. { - SyncTestFile config3(init_sync_manager.app(), "schema-version-test"); + SyncTestFile config3(user, "schema-version-test"); config3.path = config2.path; config3.schema_version = 1; config3.schema = Schema{ diff --git a/test/object-store/sync/session/wait_for_completion.cpp b/test/object-store/sync/session/wait_for_completion.cpp index 02f164d973d..c4fbb576b4e 100644 --- a/test/object-store/sync/session/wait_for_completion.cpp +++ b/test/object-store/sync/session/wait_for_completion.cpp @@ -32,20 +32,14 @@ TEST_CASE("SyncSession: wait_for_download_completion() API", "[sync][pbs][sessio if (!EventLoop::has_implementation()) return; - const std::string dummy_device_id = "123400000000000000000000"; - - // Disable file-related functionality and metadata functionality for testing purposes. - TestSyncManager::Config config; - config.metadata_mode = SyncManager::MetadataMode::NoMetadata; - TestSyncManager init_sync_manager(config, {false}); - auto& server = init_sync_manager.sync_server(); - auto sync_manager = init_sync_manager.app()->sync_manager(); + TestSyncManager tsm({}, {false}); + auto& server = tsm.sync_server(); + auto sync_manager = tsm.sync_manager(); std::atomic handler_called(false); SECTION("works properly when called after the session is bound") { server.start(); - auto user = sync_manager->get_user("user-async-wait-download-1", ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + auto user = tsm.fake_user(); auto session = sync_session(user, "/async-wait-download-1", [](auto, auto) {}); EventLoop::main().run_until([&] { return sessions_are_active(*session); @@ -61,9 +55,7 @@ TEST_CASE("SyncSession: wait_for_download_completion() API", "[sync][pbs][sessio SECTION("works properly when called on a logged-out session") { server.start(); - const auto user_id = "user-async-wait-download-3"; - auto user = sync_manager->get_user(user_id, ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + auto user = tsm.fake_user(); auto session = sync_session(user, "/user-async-wait-download-3", [](auto, auto) {}); EventLoop::main().run_until([&] { return sessions_are_active(*session); @@ -80,8 +72,8 @@ TEST_CASE("SyncSession: wait_for_download_completion() API", "[sync][pbs][sessio spin_runloop(); REQUIRE(handler_called == false); // Log the user back in - user = sync_manager->get_user(user_id, ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + user = sync_manager->get_user(user->identity(), ENCODE_FAKE_JWT("not_a_real_token"), + ENCODE_FAKE_JWT("not_a_real_token"), ""); EventLoop::main().run_until([&] { return sessions_are_active(*session); }); @@ -92,8 +84,7 @@ TEST_CASE("SyncSession: wait_for_download_completion() API", "[sync][pbs][sessio } SECTION("aborts properly when queued and the session errors out") { - auto user = sync_manager->get_user("user-async-wait-download-4", ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + auto user = tsm.fake_user(); std::atomic error_count(0); std::shared_ptr session = sync_session(user, "/async-wait-download-4", [&](auto, auto) { ++error_count; @@ -120,22 +111,17 @@ TEST_CASE("SyncSession: wait_for_upload_completion() API", "[sync][pbs][session] if (!EventLoop::has_implementation()) return; - const std::string dummy_device_id = "123400000000000000000000"; - - // Disable file-related functionality and metadata functionality for testing purposes. TestSyncManager::Config config; - config.metadata_mode = SyncManager::MetadataMode::NoMetadata; config.should_teardown_test_directory = false; SyncServer::Config server_config = {false}; - TestSyncManager init_sync_manager(config, server_config); - auto& server = init_sync_manager.sync_server(); - auto sync_manager = init_sync_manager.app()->sync_manager(); + TestSyncManager tsm(config, server_config); + auto& server = tsm.sync_server(); + auto sync_manager = tsm.sync_manager(); std::atomic handler_called(false); SECTION("works properly when called after the session is bound") { server.start(); - auto user = sync_manager->get_user("user-async-wait-upload-1", ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + auto user = tsm.fake_user(); auto session = sync_session(user, "/async-wait-upload-1", [](auto, auto) {}); EventLoop::main().run_until([&] { return sessions_are_active(*session); @@ -152,8 +138,7 @@ TEST_CASE("SyncSession: wait_for_upload_completion() API", "[sync][pbs][session] SECTION("works properly when called on a logged-out session") { server.start(); const auto user_id = "user-async-wait-upload-3"; - auto user = sync_manager->get_user(user_id, ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + auto user = tsm.fake_user(); auto session = sync_session(user, "/user-async-wait-upload-3", [](auto, auto) {}); EventLoop::main().run_until([&] { return sessions_are_active(*session); @@ -170,8 +155,8 @@ TEST_CASE("SyncSession: wait_for_upload_completion() API", "[sync][pbs][session] spin_runloop(); REQUIRE(handler_called == false); // Log the user back in - user = sync_manager->get_user(user_id, ENCODE_FAKE_JWT("not_a_real_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + user = sync_manager->get_user(user->identity(), ENCODE_FAKE_JWT("not_a_real_token"), + ENCODE_FAKE_JWT("not_a_real_token"), ""); EventLoop::main().run_until([&] { return sessions_are_active(*session); }); diff --git a/test/object-store/sync/sync_manager.cpp b/test/object-store/sync/sync_manager.cpp index f6e086dfbda..ea07c3403ac 100644 --- a/test/object-store/sync/sync_manager.cpp +++ b/test/object-store/sync/sync_manager.cpp @@ -66,42 +66,36 @@ TEST_CASE("sync_manager: `path_for_realm` API", "[sync][sync manager]") { const std::string raw_url = "realms://realm.example.org/a/b/~/123456/xyz"; SECTION("should work properly without metadata") { - TestSyncManager tsm(SyncManager::MetadataMode::NoMetadata); - auto sync_manager = tsm.app()->sync_manager(); - const std::string identity = random_string(10); - auto base_path = fs::path{tsm.base_file_path()}.make_preferred() / "mongodb-realm" / "app_id" / identity; + TestSyncManager tsm; + auto user = tsm.fake_user(); + auto base_path = fs::path{tsm.base_file_path()}.make_preferred() / "mongodb-realm" / "app_id" / user->identity(); const auto expected = base_path / "realms%3A%2F%2Frealm.example.org%2Fa%2Fb%2F%7E%2F123456%2Fxyz.realm"; - auto user = tsm.app()->sync_manager()->get_user(identity, ENCODE_FAKE_JWT("dummy_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); - REQUIRE(user->identity() == identity); SyncConfig config(user, bson::Bson{}); - REQUIRE(tsm.app()->sync_manager()->path_for_realm(config, raw_url) == expected); + REQUIRE(tsm.sync_manager()->path_for_realm(config, raw_url) == expected); // This API should also generate the directory if it doesn't already exist. REQUIRE_DIR_PATH_EXISTS(base_path); } SECTION("should work properly with metadata") { TestSyncManager tsm(SyncManager::MetadataMode::NoEncryption); - auto sync_manager = tsm.app()->sync_manager(); + auto sync_manager = tsm.sync_manager(); const std::string identity = random_string(10); auto base_path = fs::path{tsm.base_file_path()}.make_preferred() / "mongodb-realm" / "app_id" / identity; const auto expected = base_path / "realms%3A%2F%2Frealm.example.org%2Fa%2Fb%2F%7E%2F123456%2Fxyz.realm"; - auto user = tsm.app()->sync_manager()->get_user(identity, ENCODE_FAKE_JWT("dummy_token"), + auto user = tsm.sync_manager()->get_user(identity, ENCODE_FAKE_JWT("dummy_token"), ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); REQUIRE(user->identity() == identity); SyncConfig config(user, bson::Bson{}); - REQUIRE(tsm.app()->sync_manager()->path_for_realm(config, raw_url) == expected); + REQUIRE(tsm.sync_manager()->path_for_realm(config, raw_url) == expected); // This API should also generate the directory if it doesn't already exist. REQUIRE_DIR_PATH_EXISTS(base_path); } SECTION("should produce the expected path for all partition key types") { - TestSyncManager tsm(SyncManager::MetadataMode::NoMetadata); - auto sync_manager = tsm.app()->sync_manager(); - const std::string identity = random_string(10); - auto base_path = fs::path{tsm.base_file_path()}.make_preferred() / "mongodb-realm" / "app_id" / identity; - auto user = tsm.app()->sync_manager()->get_user(identity, ENCODE_FAKE_JWT("dummy_token"), - ENCODE_FAKE_JWT("not_a_real_token"), dummy_device_id); + TestSyncManager tsm; + auto sync_manager = tsm.sync_manager(); + auto user = tsm.fake_user(); + auto base_path = fs::path{tsm.base_file_path()}.make_preferred() / "mongodb-realm" / "app_id" / user->identity(); // Directory should not be created until we get the path REQUIRE_DIR_PATH_DOES_NOT_EXIST(base_path); @@ -201,7 +195,7 @@ TEST_CASE("sync_manager: `path_for_realm` API", "[sync][sync manager]") { TEST_CASE("sync_manager: user state management", "[sync][sync manager]") { TestSyncManager init_sync_manager(SyncManager::MetadataMode::NoEncryption); - auto sync_manager = init_sync_manager.app()->sync_manager(); + auto sync_manager = init_sync_manager.sync_manager(); const std::string r_token_1 = ENCODE_FAKE_JWT("foo_token"); const std::string r_token_2 = ENCODE_FAKE_JWT("bar_token"); @@ -324,7 +318,7 @@ TEST_CASE("sync_manager: persistent user state management", "[sync][sync manager SECTION("they should be added to the active users list when metadata is enabled") { config.metadata_mode = SyncManager::MetadataMode::NoEncryption; TestSyncManager tsm(config); - auto users = tsm.app()->sync_manager()->all_users(); + auto users = tsm.sync_manager()->all_users(); REQUIRE(users.size() == 3); REQUIRE(validate_user_in_vector(users, identity_1, r_token_1, a_token_1, dummy_device_id)); REQUIRE(validate_user_in_vector(users, identity_2, r_token_2, a_token_2, dummy_device_id)); @@ -334,7 +328,7 @@ TEST_CASE("sync_manager: persistent user state management", "[sync][sync manager SECTION("they should not be added to the active users list when metadata is disabled") { config.metadata_mode = SyncManager::MetadataMode::NoMetadata; TestSyncManager tsm(config); - auto users = tsm.app()->sync_manager()->all_users(); + auto users = tsm.sync_manager()->all_users(); REQUIRE(users.size() == 0); } } @@ -394,7 +388,7 @@ TEST_CASE("sync_manager: persistent user state management", "[sync][sync manager std::vector paths; { - auto sync_manager = tsm.app()->sync_manager(); + auto sync_manager = tsm.sync_manager(); // Pre-populate the user directories. auto user1 = sync_manager->get_user(u1->identity(), r_token_1, a_token_1, dummy_device_id); @@ -435,7 +429,7 @@ TEST_CASE("sync_manager: persistent user state management", "[sync][sync manager config.should_teardown_test_directory = false; SECTION("they should be cleaned up if metadata is enabled") { TestSyncManager tsm(config); - auto users = tsm.app()->sync_manager()->all_users(); + auto users = tsm.sync_manager()->all_users(); REQUIRE(users.size() == 1); REQUIRE(validate_user_in_vector(users, identity_3, r_token_3, a_token_3, dummy_device_id)); REQUIRE_REALM_DOES_NOT_EXIST(paths[0]); @@ -453,7 +447,7 @@ TEST_CASE("sync_manager: persistent user state management", "[sync][sync manager config.should_teardown_test_directory = true; config.metadata_mode = SyncManager::MetadataMode::NoMetadata; TestSyncManager tsm(config); - auto users = tsm.app()->sync_manager()->all_users(); + auto users = tsm.sync_manager()->all_users(); for (auto& path : paths) { REQUIRE_REALM_EXISTS(path); } @@ -502,7 +496,7 @@ TEST_CASE("sync_manager: file actions", "[sync][sync manager]") { TestSyncManager tsm(config); manager.make_file_action_metadata(realm_path_1, Action::DeleteRealm); - REQUIRE_FALSE(tsm.app()->sync_manager()->immediately_run_file_actions(realm_path_1)); + REQUIRE_FALSE(tsm.sync_manager()->immediately_run_file_actions(realm_path_1)); } #endif @@ -633,7 +627,7 @@ TEST_CASE("sync_manager: file actions", "[sync][sync manager]") { manager.make_file_action_metadata(realm_path_4, Action::BackUpThenDeleteRealm, recovery_1); REQUIRE(manager.all_pending_actions().size() == 1); // Force the recovery. (In a real application, the user would have closed the files by now.) - REQUIRE(tsm.app()->sync_manager()->immediately_run_file_actions(realm_path_4)); + REQUIRE(tsm.sync_manager()->immediately_run_file_actions(realm_path_4)); // There should be recovery files. REQUIRE_REALM_DOES_NOT_EXIST(realm_path_4); CHECK(File::exists(recovery_1)); @@ -689,7 +683,7 @@ TEST_CASE("sync_manager: file actions", "[sync][sync manager]") { CHECK(File::exists(recovery_3)); // the copy was successful CHECK(File::exists(realm_path_3)); // the delete failed // try again with proper permissions - REQUIRE(tsm.app()->sync_manager()->immediately_run_file_actions(realm_path_3)); + REQUIRE(tsm.sync_manager()->immediately_run_file_actions(realm_path_3)); REQUIRE(manager.all_pending_actions().size() == 0); // Realms should all be deleted. REQUIRE_REALM_DOES_NOT_EXIST(realm_path_1); @@ -727,7 +721,7 @@ TEST_CASE("sync_manager: set_session_multiplexing", "[sync][sync manager]") { tsm_config.start_sync_client = false; TestSyncManager tsm(std::move(tsm_config)); bool sync_multiplexing_allowed = GENERATE(true, false); - auto sync_manager = tsm.app()->sync_manager(); + auto sync_manager = tsm.sync_manager(); sync_manager->set_session_multiplexing(sync_multiplexing_allowed); auto user_1 = sync_manager->get_user("user-name-1", ENCODE_FAKE_JWT("not_a_real_token"), @@ -760,7 +754,7 @@ TEST_CASE("sync_manager: set_session_multiplexing", "[sync][sync manager]") { TEST_CASE("sync_manager: has_existing_sessions", "[sync][sync manager][active sessions]") { TestSyncManager init_sync_manager({}, {false}); - auto sync_manager = init_sync_manager.app()->sync_manager(); + auto sync_manager = init_sync_manager.sync_manager(); SECTION("no active sessions") { REQUIRE(!sync_manager->has_existing_sessions()); diff --git a/test/object-store/sync/user.cpp b/test/object-store/sync/user.cpp index 132b0919003..058b0914b34 100644 --- a/test/object-store/sync/user.cpp +++ b/test/object-store/sync/user.cpp @@ -36,7 +36,7 @@ static const std::string dummy_device_id = "123400000000000000000000"; TEST_CASE("sync_user: SyncManager `get_user()` API", "[sync][user]") { TestSyncManager init_sync_manager; - auto sync_manager = init_sync_manager.app()->sync_manager(); + auto sync_manager = init_sync_manager.sync_manager(); const std::string identity = "sync_test_identity"; const std::string refresh_token = ENCODE_FAKE_JWT("1234567890-fake-refresh-token"); const std::string access_token = ENCODE_FAKE_JWT("1234567890-fake-access-token"); @@ -86,7 +86,7 @@ TEST_CASE("sync_user: SyncManager `get_user()` API", "[sync][user]") { TEST_CASE("sync_user: update state and tokens", "[sync][user]") { TestSyncManager init_sync_manager; - auto sync_manager = init_sync_manager.app()->sync_manager(); + auto sync_manager = init_sync_manager.sync_manager(); const std::string identity = "sync_test_identity"; const std::string refresh_token = ENCODE_FAKE_JWT("fake-refresh-token-1"); const std::string access_token = ENCODE_FAKE_JWT("fake-access-token-1"); @@ -113,8 +113,8 @@ TEST_CASE("sync_user: update state and tokens", "[sync][user]") { } TEST_CASE("sync_user: SyncManager get_existing_logged_in_user() API", "[sync][user]") { - TestSyncManager init_sync_manager(SyncManager::MetadataMode::NoMetadata); - auto sync_manager = init_sync_manager.app()->sync_manager(); + TestSyncManager init_sync_manager; + auto sync_manager = init_sync_manager.sync_manager(); const std::string identity = "sync_test_identity"; const std::string refresh_token = ENCODE_FAKE_JWT("1234567890-fake-refresh-token"); const std::string access_token = ENCODE_FAKE_JWT("1234567890-fake-access-token"); @@ -165,8 +165,8 @@ TEST_CASE("sync_user: SyncManager get_existing_logged_in_user() API", "[sync][us } TEST_CASE("sync_user: logout", "[sync][user]") { - TestSyncManager init_sync_manager(SyncManager::MetadataMode::NoMetadata); - auto sync_manager = init_sync_manager.app()->sync_manager(); + TestSyncManager init_sync_manager; + auto sync_manager = init_sync_manager.sync_manager(); const std::string identity = "sync_test_identity"; const std::string refresh_token = ENCODE_FAKE_JWT("1234567890-fake-refresh-token"); const std::string access_token = ENCODE_FAKE_JWT("1234567890-fake-access-token"); @@ -181,7 +181,7 @@ TEST_CASE("sync_user: logout", "[sync][user]") { TEST_CASE("sync_user: user persistence", "[sync][user]") { TestSyncManager tsm(SyncManager::MetadataMode::NoEncryption); - auto sync_manager = tsm.app()->sync_manager(); + auto sync_manager = tsm.sync_manager(); auto file_manager = SyncFileManager(tsm.base_file_path(), tsm.app()->config().app_id); // Open the metadata separately, so we can investigate it ourselves. SyncMetadataManager manager(file_manager.metadata_path(), false); diff --git a/test/object-store/util/sync/sync_test_utils.cpp b/test/object-store/util/sync/sync_test_utils.cpp index 6ce6344af50..a4a2d88531e 100644 --- a/test/object-store/util/sync/sync_test_utils.cpp +++ b/test/object-store/util/sync/sync_test_utils.cpp @@ -200,7 +200,7 @@ void wait_for_sessions_to_close(const TestAppSession& test_app_session) { timed_sleeping_wait_for( [&]() -> bool { - return !test_app_session.app()->sync_manager()->has_existing_sessions(); + return !test_app_session.sync_manager()->has_existing_sessions(); }, std::chrono::minutes(5), std::chrono::milliseconds(100)); } @@ -547,7 +547,7 @@ struct BaasClientReset : public TestClientReset { { m_did_run = true; const AppSession& app_session = m_test_app_session.app_session(); - auto sync_manager = m_test_app_session.app()->sync_manager(); + auto sync_manager = m_test_app_session.sync_manager(); std::string partition_value = m_local_config.sync_config->partition_value; REALM_ASSERT(partition_value.size() > 2 && *partition_value.begin() == '"' && *(partition_value.end() - 1) == '"'); diff --git a/test/object-store/util/test_file.hpp b/test/object-store/util/test_file.hpp index 552550bdba3..a657802f27c 100644 --- a/test/object-store/util/test_file.hpp +++ b/test/object-store/util/test_file.hpp @@ -206,6 +206,10 @@ class TestAppSession { { return m_transport.get(); } + const std::shared_ptr& sync_manager() const + { + return m_app->sync_manager(); + } std::vector get_documents(realm::SyncUser& user, const std::string& object_type, size_t expected_count) const; @@ -249,6 +253,10 @@ class TestSyncManager { { return m_sync_server; } + const std::shared_ptr& sync_manager() + { + return m_app->sync_manager(); + } std::shared_ptr fake_user(const std::string& name = "test");