From 1ca0865ec73238b5247ff557c934c8140f9d45b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Wed, 25 Aug 2021 16:10:54 +0200 Subject: [PATCH] Workaround issue when initiating sync on a copied realm file The problem is that the server does not know that the client has already integrated some server versions, and therefore it sends down 0 as progress/upload/last_integrated_server_version. On the client this number may be bigger and in this case that number will not be overwritten with 0. There may still be issues on the server, however. --- src/realm/sync/noinst/client_history_impl.cpp | 12 +- test/object-store/sync/app.cpp | 121 ++++++++++++++++++ 2 files changed, 129 insertions(+), 4 deletions(-) diff --git a/src/realm/sync/noinst/client_history_impl.cpp b/src/realm/sync/noinst/client_history_impl.cpp index 29466f26624..f4f5ac14168 100644 --- a/src/realm/sync/noinst/client_history_impl.cpp +++ b/src/realm/sync/noinst/client_history_impl.cpp @@ -953,8 +953,10 @@ void ClientHistoryImpl::update_sync_progress(const SyncProgress& progress, version_type(root.get_as_ref_or_tagged(s_progress_download_client_version_iip).get_as_int())); REALM_ASSERT(progress.upload.client_version >= version_type(root.get_as_ref_or_tagged(s_progress_upload_client_version_iip).get_as_int())); - REALM_ASSERT(progress.upload.last_integrated_server_version >= - version_type(root.get_as_ref_or_tagged(s_progress_upload_server_version_iip).get_as_int())); + if (progress.upload.last_integrated_server_version > 0) { + REALM_ASSERT(progress.upload.last_integrated_server_version >= + version_type(root.get_as_ref_or_tagged(s_progress_upload_server_version_iip).get_as_int())); + } auto uploaded_bytes = std::uint_fast64_t(root.get_as_ref_or_tagged(s_progress_uploaded_bytes_iip).get_as_int()); auto previous_upload_client_version = @@ -971,8 +973,10 @@ void ClientHistoryImpl::update_sync_progress(const SyncProgress& progress, RefOrTagged::make_tagged(progress.latest_server_version.salt)); // Throws root.set(s_progress_upload_client_version_iip, RefOrTagged::make_tagged(progress.upload.client_version)); // Throws - root.set(s_progress_upload_server_version_iip, - RefOrTagged::make_tagged(progress.upload.last_integrated_server_version)); // Throws + if (progress.upload.last_integrated_server_version > 0) { + root.set(s_progress_upload_server_version_iip, + RefOrTagged::make_tagged(progress.upload.last_integrated_server_version)); // Throws + } if (downloadable_bytes) { root.set(s_progress_downloadable_bytes_iip, RefOrTagged::make_tagged(*downloadable_bytes)); // Throws diff --git a/test/object-store/sync/app.cpp b/test/object-store/sync/app.cpp index 4cf35814cfa..04333b47c51 100644 --- a/test/object-store/sync/app.cpp +++ b/test/object-store/sync/app.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "util/baas_admin_api.hpp" #include "util/event_loop.hpp" @@ -1988,6 +1989,126 @@ TEST_CASE("app: set new embedded object", "[sync][app]") { } } +TEST_CASE("app: make distributable client file", "[sync][app]") { + std::unique_ptr (*factory)() = [] { + return std::unique_ptr(new IntTestTransport); + }; + std::string base_url = get_base_url(); + REQUIRE(!base_url.empty()); + auto app_session = get_runtime_app_session(base_url); + + auto app_id = app_session.client_app_id; + auto config = App::Config{app_id, + factory, + base_url, + util::none, + Optional("A Local App Version"), + util::none, + "Object Store Platform Tests", + "Object Store Platform Version Blah", + "An sdk version"}; + + auto base_path = util::make_temp_dir(); + util::try_remove_dir_recursive(base_path); + util::try_make_dir(base_path); + util::try_make_dir(base_path + "/orig"); + util::try_make_dir(base_path + "/copy"); + + // Create realm file without client file id + { + TestSyncManager sync_manager(TestSyncManager::Config(config), {}); + auto app = sync_manager.app(); + app->log_in_with_credentials(AppCredentials::anonymous(), + [&](std::shared_ptr user, Optional error) { + REQUIRE(!error); + REQUIRE(user); + }); + + ThreadSafeReference realm_ref; + + realm::Realm::Config realm_config; + realm_config.sync_config = std::make_shared(app->current_user(), bson::Bson("foo")); + realm_config.sync_config->client_resync_mode = ClientResyncMode::Manual; + realm_config.sync_config->error_handler = [](std::shared_ptr, SyncError error) { + std::cerr << error.message << std::endl; + }; + realm_config.schema_version = 1; + realm_config.path = base_path + "/orig/default.realm"; + + std::mutex mutex; + auto task = realm::Realm::get_synchronized_realm(realm_config); + task->start([&](ThreadSafeReference ref, std::exception_ptr error) { + std::lock_guard lock(mutex); + REQUIRE(!error); + realm_ref = std::move(ref); + }); + util::EventLoop::main().run_until([&] { + std::lock_guard lock(mutex); + return bool(realm_ref); + }); + SharedRealm realm = Realm::get_shared_realm(std::move(realm_ref)); + + // Write some data + realm->begin_transaction(); + CppContext c; + Object::create(c, realm, "Person", + util::Any(realm::AnyDict{{"_id", util::Any(ObjectId::gen())}, + {"age", INT64_C(64)}, + {"firstName", std::string("Paul")}, + {"lastName", std::string("McCartney")}})); + realm->commit_transaction(); + wait_for_upload(*realm); + wait_for_download(*realm); + + realm->write_copy(base_path + "/copy/default.realm", BinaryData()); + + // Write some additional data + realm->begin_transaction(); + Object::create(c, realm, "Dog", + util::Any(realm::AnyDict{{"_id", util::Any(ObjectId::gen())}, + {"breed", std::string("stabyhoun")}, + {"name", std::string("albert")}, + {"realm_id", std::string("foo")}})); + realm->commit_transaction(); + wait_for_upload(*realm); + } + // Starting a new session based on the copy + { + TestSyncManager sync_manager(TestSyncManager::Config(config), {}); + auto app = sync_manager.app(); + app->log_in_with_credentials(AppCredentials::anonymous(), + [&](std::shared_ptr user, Optional error) { + REQUIRE(!error); + REQUIRE(user); + }); + + ThreadSafeReference realm_ref; + + realm::Realm::Config realm_config; + realm_config.sync_config = std::make_shared(app->current_user(), bson::Bson("foo")); + realm_config.sync_config->client_resync_mode = ClientResyncMode::Manual; + realm_config.sync_config->error_handler = [](std::shared_ptr, SyncError error) { + std::cerr << error.message << std::endl; + }; + realm_config.schema_version = 1; + realm_config.path = base_path + "/copy/default.realm"; + + SharedRealm realm = realm::Realm::get_shared_realm(realm_config); + wait_for_download(*realm); + + // Check that we can continue committing to this realm + realm->begin_transaction(); + CppContext c; + Object::create(c, realm, "Dog", + util::Any(realm::AnyDict{{"_id", util::Any(ObjectId::gen())}, + {"breed", std::string("bulldog")}, + {"name", std::string("fido")}, + {"realm_id", std::string("foo")}})); + realm->commit_transaction(); + wait_for_upload(*realm); + } +} + TEST_CASE("app: sync integration", "[sync][app]") { std::unique_ptr (*factory)() = [] { return std::unique_ptr(new IntTestTransport);