Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace TestAppSession close()/reopen() with scope based TestAppSession instance #7672

Merged
merged 22 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5f72d0c
Updated TestAppSession to remove close/reopen and take a config struc…
May 2, 2024
217a9f1
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
May 2, 2024
3a64207
Updated changelog and minor tweaks
May 2, 2024
61d3236
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
May 3, 2024
ee3cff2
AutoVerify email address matters...
May 3, 2024
bffec15
Forgot to adjust format string
May 3, 2024
e5d6391
Updated REQUIRE's in TestAppSession to REALM_ASSERTs due to thread sa…
May 3, 2024
c7e20d1
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
May 30, 2024
631bb04
Some minor cleanup
May 30, 2024
4a2d00c
a little more cleanup
May 30, 2024
e950105
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
May 31, 2024
bf3c8f5
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Jun 3, 2024
03b45b6
Updated changelog after release
Jun 3, 2024
35ba056
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Jun 4, 2024
1659dbb
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Jun 4, 2024
42dea77
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Jun 4, 2024
edb7b25
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Jun 7, 2024
bb9b766
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Jun 14, 2024
4a0ac6c
Updated changelog after release
Jun 15, 2024
1591bfa
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Jul 2, 2024
21eb8a3
Updated changelog
Jul 2, 2024
857c99c
Merge branch 'master' of github.com:realm/realm-core into mwb/fix-tes…
Aug 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
### Internals
* Fixed `Table::remove_object_recursive` which wouldn't recursively follow links through a single `Mixed` property. This feature is exposed publicly on `Table` but no SDK currently uses it, so this is considered internal. ([#7829](https://github.com/realm/realm-core/issues/7829), likely since the introduction of Mixed)
* Upload completion is now tracked in a multiprocess-compatible manner ([PR #7796](https://github.com/realm/realm-core/pull/7796)).
* Update TestAppSession to allow scope-based usage for restarting the local app resources. ([PR #7672](https://github.com/realm/realm-core/pull/7672))

----------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion test/object-store/c_api/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6372,7 +6372,7 @@ TEST_CASE("C API app: link_user integration w/c_api transport", "[sync][app][c_a
auto user_data = new TestTransportUserData();
auto http_transport = realm_http_transport_new(send_request_to_server, user_data, user_data_free);
auto app_session = get_runtime_app_session();
TestAppSession session(app_session, *http_transport, DeleteApp{false});
TestAppSession session(app_session, {*http_transport}, DeleteApp{false});
realm_app app(session.app());

SECTION("remove_user integration") {
Expand Down
26 changes: 16 additions & 10 deletions test/object-store/realm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1464,16 +1464,22 @@ TEST_CASE("Synchronized realm: AutoOpen", "[sync][baas][pbs][async open]") {
std::mutex mutex;

// Create the app session and get the logged in user identity
auto server_app_config = minimal_app_config("autoopen-realm", schema);
TestAppSession session(create_app(server_app_config), transport, DeleteApp{true}, realm::ReconnectMode::normal,
socket_provider);
auto user = session.app()->current_user();
std::string identity = user->user_id();
REQUIRE(user->is_logged_in());
REQUIRE(!identity.empty());
// Reopen the App instance and retrieve the cached user
session.reopen(false);
user = session.app()->get_existing_logged_in_user(identity);
auto app_session = create_app(minimal_app_config("autoopen-realm", schema));
std::string identity;
TestAppSession::Config tas_config;
{
// Keep the app and realm storage
TestAppSession session(app_session, {transport, realm::ReconnectMode::normal, socket_provider},
DeleteApp{false}, false);
auto user = session.current_user();
REQUIRE(user);
REQUIRE(user->is_logged_in());
identity = user->user_id();
tas_config = session.config(); // get config with storage path and user creds populated
}
REQUIRE_FALSE(identity.empty());
TestAppSession session(app_session, tas_config);
auto user = session.app()->get_existing_logged_in_user(identity);

SyncTestFile config(user, partition, schema);
config.sync_config->cancel_waits_on_nonfatal_error = true;
Expand Down
10 changes: 5 additions & 5 deletions test/object-store/sync/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2158,7 +2158,7 @@ TEST_CASE("app: mixed lists with object links", "[sync][pbs][app][links][baas]")
Mixed{target_id},
};
{
TestAppSession test_session(app_session, nullptr, DeleteApp{false});
TestAppSession test_session(app_session, {}, DeleteApp{false});
SyncTestFile config(test_session.app()->current_user(), partition, schema);
auto realm = Realm::get_shared_realm(config);

Expand Down Expand Up @@ -2222,7 +2222,7 @@ TEST_CASE("app: roundtrip values", "[sync][pbs][app][baas]") {
Decimal128 large_significand = Decimal128(70) / Decimal128(1.09);
auto obj_id = ObjectId::gen();
{
TestAppSession test_session(app_session, nullptr, DeleteApp{false});
TestAppSession test_session(app_session, {}, DeleteApp{false});
SyncTestFile config(test_session.app()->current_user(), partition, schema);
auto realm = Realm::get_shared_realm(config);

Expand Down Expand Up @@ -2646,7 +2646,7 @@ TEST_CASE("app: sync integration", "[sync][pbs][app][baas]") {
}

auto transport = std::make_shared<HookedTransport<>>();
TestAppSession hooked_session(session.app_session(), transport, DeleteApp{false});
TestAppSession hooked_session(session.app_session(), {transport}, DeleteApp{false});
auto app = hooked_session.app();
std::shared_ptr<User> user = app->current_user();
REQUIRE(user);
Expand Down Expand Up @@ -2704,7 +2704,7 @@ TEST_CASE("app: sync integration", "[sync][pbs][app][baas]") {
}

auto transport = std::make_shared<HookedTransport<>>();
TestAppSession hooked_session(session.app_session(), transport, DeleteApp{false});
TestAppSession hooked_session(session.app_session(), {transport}, DeleteApp{false});
auto app = hooked_session.app();
std::shared_ptr<User> user = app->current_user();
REQUIRE(user);
Expand Down Expand Up @@ -4460,7 +4460,7 @@ TEST_CASE("app: full-text compatible with sync", "[sync][app][baas]") {
auto server_app_config = minimal_app_config("full_text", schema);
auto app_session = create_app(server_app_config);
const auto partition = random_string(100);
TestAppSession test_session(app_session, nullptr);
TestAppSession test_session(app_session);
SyncTestFile config(test_session.app()->current_user(), partition, schema);
SharedRealm realm;
SECTION("sync open") {
Expand Down
9 changes: 5 additions & 4 deletions test/object-store/util/sync/flx_sync_harness.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,17 @@ class FLXSyncTestHarness {
};

explicit FLXSyncTestHarness(Config&& config)
: m_test_session(make_app_from_server_schema(config.test_name, config.server_schema), config.transport, true,
config.reconnect_mode, config.custom_socket_provider)
: m_test_session(make_app_from_server_schema(config.test_name, config.server_schema),
{config.transport, config.reconnect_mode, config.custom_socket_provider}, DeleteApp{true})
, m_schema(std::move(config.server_schema.schema))
{
}
FLXSyncTestHarness(const std::string& test_name, ServerSchema server_schema = default_server_schema(),
std::shared_ptr<GenericNetworkTransport> transport = instance_of<SynchronousTestTransport>,
std::shared_ptr<realm::sync::SyncSocketProvider> custom_socket_provider = nullptr)
: m_test_session(make_app_from_server_schema(test_name, server_schema), std::move(transport), true,
realm::ReconnectMode::normal, custom_socket_provider)
: m_test_session(make_app_from_server_schema(test_name, server_schema),
{std::move(transport), realm::ReconnectMode::normal, custom_socket_provider},
DeleteApp{true})
, m_schema(std::move(server_schema.schema))
{
}
Expand Down
145 changes: 83 additions & 62 deletions test/object-store/util/test_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,102 +329,123 @@ void set_app_config_defaults(app::AppConfig& app_config,
#if REALM_ENABLE_AUTH_TESTS

TestAppSession::TestAppSession()
: TestAppSession(get_runtime_app_session(), nullptr, DeleteApp{false})
// Don't delete the global runtime app session
: TestAppSession(get_runtime_app_session(), {}, DeleteApp{false})
{
}

TestAppSession::TestAppSession(AppSession session,
std::shared_ptr<realm::app::GenericNetworkTransport> custom_transport,
DeleteApp delete_app, ReconnectMode reconnect_mode,
std::shared_ptr<realm::sync::SyncSocketProvider> custom_socket_provider)
TestAppSession::TestAppSession(AppSession session)
: TestAppSession(session, {}, DeleteApp{true})
{
}

TestAppSession::TestAppSession(AppSession session, Config config, DeleteApp delete_app, bool delete_storage)
: m_app_session(std::make_unique<AppSession>(session))
, m_base_file_path(util::make_temp_dir() + random_string(10))
, m_config(config)
, m_delete_app(delete_app)
, m_transport(custom_transport)
, m_delete_storage(delete_storage)
{
if (!m_transport)
m_transport = instance_of<SynchronousTestTransport>;
app_config = get_config(m_transport, *m_app_session);
set_app_config_defaults(app_config, m_transport);
app_config.base_file_path = m_base_file_path;
app_config.metadata_mode = realm::app::AppConfig::MetadataMode::NoEncryption;
if (!m_config.storage_path || m_config.storage_path->empty()) {
m_config.storage_path.emplace(util::make_temp_dir() + random_string(10));
}
REALM_ASSERT(m_config.storage_path);
util::try_make_dir(*m_config.storage_path);

util::try_make_dir(m_base_file_path);
app_config.sync_client_config.reconnect_mode = reconnect_mode;
app_config.sync_client_config.socket_provider = custom_socket_provider;
if (!m_config.transport) {
m_config.transport = instance_of<SynchronousTestTransport>;
}
realm::app::AppConfig app_config = get_config(m_config.transport, *m_app_session);
set_app_config_defaults(app_config, m_config.transport);
// If a base URL was provided, set it in the app config
if (m_config.base_url) {
app_config.base_url = *m_config.base_url;
}
app_config.base_file_path = *m_config.storage_path;
app_config.metadata_mode = m_config.metadata_mode;
app_config.sync_client_config.reconnect_mode = m_config.reconnect_mode;
// With multiplexing enabled, the linger time controls how long a
// connection is kept open for reuse. In tests, we want to shut
// down sync clients immediately.
app_config.sync_client_config.timeouts.connection_linger_time = 0;

app_config.sync_client_config.socket_provider = m_config.socket_provider;
m_app = app::App::get_app(app::App::CacheMode::Disabled, app_config);

// initialize sync client
m_app->sync_manager()->get_sync_client();
user_creds = create_user_and_log_in(m_app);
// If no user creds are supplied, then create the user and log in
if (!m_config.user_creds) {
auto result = create_user_and_log_in();
REALM_ASSERT(result.is_ok());
m_config.user_creds = result.get_value();
}
// If creds are supplied, it is up to the caller to log in separately
}

TestAppSession::~TestAppSession()
{
if (util::File::exists(m_base_file_path)) {
if (m_app) {
m_app->sync_manager()->tear_down_for_testing();
m_app.reset();
}
app::App::clear_cached_apps();
// If the app session is being deleted or the config tells us to, delete the storage path
if ((m_delete_app || m_delete_storage) && util::File::exists(*m_config.storage_path)) {
try {
m_app->sync_manager()->tear_down_for_testing();
util::try_remove_dir_recursive(m_base_file_path);
util::try_remove_dir_recursive(*m_config.storage_path);
}
catch (const std::exception& ex) {
std::cerr << ex.what() << "\n";
std::cerr << "Error tearing down TestAppSession(" << m_app_session->config.app_name << "): " << ex.what()
<< "\n";
}
app::App::clear_cached_apps();
}
if (m_delete_app) {
if (m_delete_app && m_app_session) {
m_app_session->admin_api.delete_app(m_app_session->server_app_id);
}
}

void TestAppSession::close(bool tear_down)
StatusWith<realm::app::AppCredentials> TestAppSession::create_user_and_log_in()
{
try {
if (tear_down) {
// If tearing down, make sure there's an app to work with
if (!m_app) {
reopen(false);
REALM_ASSERT(m_app);
AutoVerifiedEmailCredentials creds;
auto pf = util::make_promise_future<void>();
m_app->provider_client<app::App::UsernamePasswordProviderClient>().register_email(
creds.email, creds.password,
[this, &creds, promise = util::CopyablePromiseHolder<void>(std::move(pf.promise))](
util::Optional<app::AppError> error) mutable {
if (error) {
promise.get_promise().set_error(error->to_status());
return;
}
REALM_ASSERT(m_app);
// Clean up the app data
m_app->sync_manager()->tear_down_for_testing();
}
else if (m_app) {
// Otherwise, make sure all the session are closed
m_app->sync_manager()->close_all_sessions();
}
m_app.reset();

// If tearing down, clean up the test file directory
if (tear_down && !m_base_file_path.empty() && util::File::exists(m_base_file_path)) {
util::try_remove_dir_recursive(m_base_file_path);
m_base_file_path.clear();
}
}
catch (const std::exception& ex) {
std::cerr << "Error tearing down TestAppSession: " << ex.what() << "\n";
auto result = log_in_user(creds);
if (!result.is_ok()) {
promise.get_promise().set_error(result.get_status());
return;
}
promise.get_promise().emplace_value();
});
auto result = pf.future.get_no_throw();
if (!result.is_ok()) {
return result;
}
// Ensure all cached apps are cleared
app::App::clear_cached_apps();
return creds;
}

void TestAppSession::reopen(bool log_in)
StatusWith<std::shared_ptr<realm::SyncUser>>
TestAppSession::log_in_user(std::optional<realm::app::AppCredentials> user_creds)
{
REALM_ASSERT(!m_base_file_path.empty());
if (m_app) {
close(false);
}
m_app = app::App::get_app(app::App::CacheMode::Disabled, app_config);

// initialize sync client
m_app->sync_manager()->get_sync_client();
if (log_in) {
log_in_user(m_app, user_creds);
}
REALM_ASSERT(m_app);
REALM_ASSERT((user_creds || m_config.user_creds));
auto pf = util::make_promise_future<std::shared_ptr<realm::SyncUser>>();
m_app->log_in_with_credentials(
*user_creds, [promise = util::CopyablePromiseHolder<std::shared_ptr<realm::SyncUser>>(std::move(pf.promise))](
std::shared_ptr<realm::SyncUser> user, util::Optional<app::AppError> error) mutable {
if (error) {
promise.get_promise().set_error(error->to_status());
return;
}
promise.get_promise().emplace_value(user);
});
return pf.future.get_no_throw();
}

std::vector<bson::BsonDocument> TestAppSession::get_documents(app::User& user, const std::string& object_type,
Expand Down
47 changes: 32 additions & 15 deletions test/object-store/util/test_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,27 @@ class OfflineAppSession {
using DeleteApp = realm::util::TaggedBool<struct DeleteAppTag>;
class TestAppSession {
public:
struct Config {
std::shared_ptr<realm::app::GenericNetworkTransport> transport;
realm::ReconnectMode reconnect_mode = realm::ReconnectMode::normal;
std::shared_ptr<realm::sync::SyncSocketProvider> socket_provider;
realm::app::AppConfig::MetadataMode metadata_mode = realm::app::AppConfig::MetadataMode::NoEncryption;
std::optional<std::string> base_url;
std::optional<std::string> storage_path;
// If user_creds are supplied, caller must explicitly call log_in_user() after TestAppSession creation
std::optional<realm::app::AppCredentials> user_creds;
};

TestAppSession();
TestAppSession(realm::AppSession, std::shared_ptr<realm::app::GenericNetworkTransport> = nullptr,
DeleteApp = true, realm::ReconnectMode reconnect_mode = realm::ReconnectMode::normal,
std::shared_ptr<realm::sync::SyncSocketProvider> custom_socket_provider = nullptr);
TestAppSession(realm::AppSession);
TestAppSession(realm::AppSession, Config, DeleteApp = true, bool delete_storage = true);

~TestAppSession();

const Config& config() const noexcept
{
return m_config;
}
std::shared_ptr<realm::app::App> app() const noexcept
{
return m_app;
Expand All @@ -339,31 +354,33 @@ class TestAppSession {
}
realm::app::GenericNetworkTransport* transport()
{
return m_transport.get();
return m_config.transport.get();
}
const std::shared_ptr<realm::SyncManager>& sync_manager() const
{
REALM_ASSERT(m_app);
return m_app->sync_manager();
}

// Close the app instance (or tear down the TestAppSession)
void close(bool tear_down = false);
// Re-open the app instance using app_config
void reopen(bool log_in = false);

realm::app::AppConfig app_config;
std::shared_ptr<realm::app::User> current_user() const
{
REALM_ASSERT(m_app);
return m_app->current_user();
}
realm::StatusWith<realm::app::AppCredentials> create_user_and_log_in();
// The user_creds from the Config structure will be used if not provided
realm::StatusWith<std::shared_ptr<realm::SyncUser>>
log_in_user(std::optional<realm::app::AppCredentials> user_creds = std::nullopt);

std::vector<realm::bson::BsonDocument> get_documents(realm::app::User& user, const std::string& object_type,
size_t expected_count) const;

private:
std::shared_ptr<realm::app::App> m_app;
std::unique_ptr<realm::AppSession> m_app_session;
std::string m_base_file_path;
bool m_delete_app = true;
std::shared_ptr<realm::app::GenericNetworkTransport> m_transport;
realm::app::AppCredentials user_creds;
Config m_config;
bool m_delete_app;
bool m_delete_storage;
std::shared_ptr<realm::app::App> m_app;
};
#endif // REALM_ENABLE_AUTH_TESTS

Expand Down
Loading