diff --git a/packages/library-base/src/commonMain/kotlin/io/realm/kotlin/internal/platform/SystemUtils.kt b/packages/library-base/src/commonMain/kotlin/io/realm/kotlin/internal/platform/SystemUtils.kt index bfec4f83b5..010b1fa9a5 100644 --- a/packages/library-base/src/commonMain/kotlin/io/realm/kotlin/internal/platform/SystemUtils.kt +++ b/packages/library-base/src/commonMain/kotlin/io/realm/kotlin/internal/platform/SystemUtils.kt @@ -59,6 +59,13 @@ public expect val DEVICE_MODEL: String */ public expect val PATH_SEPARATOR: String +/** + * Construct a path from individual components + */ +public fun pathOf(vararg pathParts: String): String { + return pathParts.joinToString(PATH_SEPARATOR) +} + /** * Returns the root directory of the platform's App data. */ diff --git a/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmConfigurationTests.kt b/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmConfigurationTests.kt index 81d0a96efd..cc9c22f728 100644 --- a/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmConfigurationTests.kt +++ b/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmConfigurationTests.kt @@ -23,6 +23,7 @@ import io.realm.kotlin.entities.Sample import io.realm.kotlin.internal.InternalConfiguration import io.realm.kotlin.internal.platform.PATH_SEPARATOR import io.realm.kotlin.internal.platform.appFilesDirectory +import io.realm.kotlin.internal.platform.pathOf import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.internal.util.CoroutineDispatcherFactory import io.realm.kotlin.log.LogLevel @@ -77,7 +78,7 @@ class RealmConfigurationTests { fun with() { val config = RealmConfiguration.create(schema = setOf(Sample::class)) assertEquals( - "${appFilesDirectory()}${PATH_SEPARATOR}${Realm.DEFAULT_FILE_NAME}", + pathOf(appFilesDirectory(), Realm.DEFAULT_FILE_NAME), config.path ) assertEquals(Realm.DEFAULT_FILE_NAME, config.name) @@ -95,7 +96,7 @@ class RealmConfigurationTests { fun defaultPath() { val config = RealmConfiguration.create(schema = setOf(Sample::class)) assertEquals( - "${appFilesDirectory()}${PATH_SEPARATOR}${Realm.DEFAULT_FILE_NAME}", + pathOf(appFilesDirectory(), Realm.DEFAULT_FILE_NAME), config.path ) @@ -103,7 +104,7 @@ class RealmConfigurationTests { RealmConfiguration.Builder(schema = setOf(Sample::class)) .build() assertEquals( - "${appFilesDirectory()}${PATH_SEPARATOR}${Realm.DEFAULT_FILE_NAME}", + pathOf(appFilesDirectory(), Realm.DEFAULT_FILE_NAME), configFromBuilderWithDefaultName.path ) @@ -112,7 +113,7 @@ class RealmConfigurationTests { .name("custom.realm") .build() assertEquals( - "${appFilesDirectory()}${PATH_SEPARATOR}custom.realm", + pathOf(appFilesDirectory(), "custom.realm"), configFromBuilderWithCustomName.path ) @@ -122,7 +123,7 @@ class RealmConfigurationTests { .name("foo.realm") .build() assertEquals( - "${appFilesDirectory()}${PATH_SEPARATOR}my_dir${PATH_SEPARATOR}foo.realm", + pathOf(appFilesDirectory(), "my_dir", "foo.realm"), configFromBuilderWithCurrentDir.path ) } @@ -133,16 +134,16 @@ class RealmConfigurationTests { val config = RealmConfiguration.Builder(schema = setOf(Sample::class)) .directory(realmDir) .build() - assertEquals("$tmpDir${PATH_SEPARATOR}${Realm.DEFAULT_FILE_NAME}", config.path) + assertEquals(pathOf(tmpDir, Realm.DEFAULT_FILE_NAME), config.path) } @Test fun directory_withSpace() { - val realmDir = tmpDir + "${PATH_SEPARATOR}dir with space" + val realmDir = pathOf(tmpDir, "dir with space") val config = RealmConfiguration.Builder(schema = setOf(Sample::class)) .directory(realmDir) .build() - assertEquals("$realmDir${PATH_SEPARATOR}${Realm.DEFAULT_FILE_NAME}", config.path) + assertEquals(pathOf(realmDir, Realm.DEFAULT_FILE_NAME), config.path) // Just verifying that we can open the realm Realm.open(config).use { } } @@ -158,7 +159,7 @@ class RealmConfigurationTests { @Test fun directory_createIntermediateDirs() { - val realmDir = tmpDir + listOf("my", "intermediate", "dir").joinToString(separator = PATH_SEPARATOR, prefix = PATH_SEPARATOR) + val realmDir = pathOf(tmpDir, "my", "intermediate", "dir") val configBuilder = RealmConfiguration.Builder(schema = setOf(Sample::class)) .directory(realmDir) @@ -168,7 +169,7 @@ class RealmConfigurationTests { @Test fun directory_isFileThrows() { - val tmpFile = "$tmpDir${PATH_SEPARATOR}file" + val tmpFile = pathOf(tmpDir, "file") platformFileSystem.write(tmpFile.toPath(), mustCreate = true) { write(ByteArray(0)) } @@ -186,7 +187,7 @@ class RealmConfigurationTests { fun directoryAndNameCombine() { val realmDir = tmpDir val realmName = "my.realm" - val expectedPath = "$realmDir${PATH_SEPARATOR}$realmName" + val expectedPath = pathOf(realmDir, realmName) val config = RealmConfiguration.Builder(setOf(Sample::class)) @@ -236,7 +237,7 @@ class RealmConfigurationTests { .directory(tmpDir) .name(name) .build() - assertEquals("$tmpDir${PATH_SEPARATOR}$name", config.path) + assertEquals(pathOf(tmpDir, name), config.path) // Just verifying that we can open the realm Realm.open(config).use { } } diff --git a/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmTests.kt b/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmTests.kt index 9ddca51450..624353f975 100644 --- a/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmTests.kt +++ b/packages/test-base/src/commonTest/kotlin/io/realm/kotlin/test/common/RealmTests.kt @@ -25,9 +25,9 @@ import io.realm.kotlin.ext.isManaged import io.realm.kotlin.ext.isValid import io.realm.kotlin.ext.query import io.realm.kotlin.ext.version -import io.realm.kotlin.internal.platform.PATH_SEPARATOR import io.realm.kotlin.internal.platform.fileExists import io.realm.kotlin.internal.platform.isWindows +import io.realm.kotlin.internal.platform.pathOf import io.realm.kotlin.query.find import io.realm.kotlin.test.common.utils.assertFailsWithMessage import io.realm.kotlin.test.platform.PlatformUtils @@ -524,7 +524,7 @@ class RealmTests { val anotherRealm = Realm.open(configA) // Deleting it without having closed it should fail. - assertFailsWithMessage("Cannot delete files of an open Realm: '$tempDirA${PATH_SEPARATOR}anotherRealm.realm' is still in use") { + assertFailsWithMessage("Cannot delete files of an open Realm: '${pathOf(tempDirA, "anotherRealm.realm")}' is still in use") { Realm.deleteRealm(configA) } diff --git a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/AppConfigurationTests.kt b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/AppConfigurationTests.kt index ee6c4f41b4..3e73576d1b 100644 --- a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/AppConfigurationTests.kt +++ b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/AppConfigurationTests.kt @@ -17,8 +17,8 @@ package io.realm.kotlin.test.mongodb.common -import io.realm.kotlin.internal.platform.PATH_SEPARATOR import io.realm.kotlin.internal.platform.appFilesDirectory +import io.realm.kotlin.internal.platform.pathOf import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.log.LogLevel import io.realm.kotlin.log.RealmLog @@ -142,7 +142,7 @@ class AppConfigurationTests { @Test fun syncRootDirectory() { val builder: AppConfiguration.Builder = AppConfiguration.Builder(APP_ID) - val expectedRoot = "${appFilesDirectory()}${PATH_SEPARATOR}myCustomDir" + val expectedRoot = pathOf(appFilesDirectory(), "myCustomDir") val config = builder .syncRootDirectory(expectedRoot) .build() @@ -160,7 +160,7 @@ class AppConfigurationTests { // the configured `AppConfiguration.syncRootDir` @Test fun syncRootDirectory_appendDirectoryToPath() = runBlocking { - val expectedRoot = "${appFilesDirectory()}${PATH_SEPARATOR}myCustomDir" + val expectedRoot = pathOf(appFilesDirectory(), "myCustomDir") TestApp("syncRootDirectory_appendDirectoryToPath", builder = { it.syncRootDirectory(expectedRoot) }).use { app -> @@ -171,7 +171,7 @@ class AppConfigurationTests { // the configured `AppConfiguration.syncRootDir` val partitionValue = TestHelper.randomPartitionValue() val suffix = - "${PATH_SEPARATOR}myCustomDir${PATH_SEPARATOR}mongodb-realm${PATH_SEPARATOR}${user.app.configuration.appId}${PATH_SEPARATOR}${user.id}${PATH_SEPARATOR}s_$partitionValue.realm" + pathOf("", "myCustomDir", "mongodb-realm", user.app.configuration.appId, user.id, "s_$partitionValue.realm") val config = SyncConfiguration.Builder(user, partitionValue, schema = setOf()).build() assertTrue(config.path.endsWith(suffix), "Failed: ${config.path} vs. $suffix") } diff --git a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/FlexibleSyncConfigurationTests.kt b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/FlexibleSyncConfigurationTests.kt index 1cd8d25aff..841def7936 100644 --- a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/FlexibleSyncConfigurationTests.kt +++ b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/FlexibleSyncConfigurationTests.kt @@ -17,6 +17,7 @@ package io.realm.kotlin.test.mongodb.common import io.realm.kotlin.Realm import io.realm.kotlin.internal.platform.PATH_SEPARATOR +import io.realm.kotlin.internal.platform.pathOf import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.mongodb.App import io.realm.kotlin.mongodb.User @@ -225,6 +226,6 @@ class FlexibleSyncConfigurationTests { val config: SyncConfiguration = SyncConfiguration.Builder(user, setOf()) .name("custom.realm") .build() - assertTrue(config.path.endsWith("${app.configuration.appId}${PATH_SEPARATOR}${user.id}${PATH_SEPARATOR}custom.realm"), "Path is: ${config.path}") + assertTrue(config.path.endsWith(pathOf(app.configuration.appId, user.id, "custom.realm")), "Path is: ${config.path}") } } diff --git a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncConfigTests.kt b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncConfigTests.kt index ffbb352aab..217516f2dd 100644 --- a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncConfigTests.kt +++ b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncConfigTests.kt @@ -30,6 +30,7 @@ import io.realm.kotlin.entities.sync.flx.FlexEmbeddedObject import io.realm.kotlin.entities.sync.flx.FlexParentObject import io.realm.kotlin.ext.query import io.realm.kotlin.internal.platform.createDefaultSystemLogger +import io.realm.kotlin.internal.platform.pathOf import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.internal.platform.singleThreadDispatcher import io.realm.kotlin.log.LogLevel @@ -406,7 +407,7 @@ class SyncConfigTests { private fun verifyName(builder: SyncConfiguration.Builder, expectedFileName: String) { val config = builder.build() - val suffix = "/mongodb-realm/${config.user.app.configuration.appId}/${config.user.identity}/$expectedFileName" + val suffix = pathOf("", "mongodb-realm", config.user.app.configuration.appId, config.user.id, expectedFileName) assertTrue(config.path.contains(suffix), "${config.path} failed.") assertEquals(expectedFileName, config.name) } @@ -1260,7 +1261,7 @@ class SyncConfigTests { val config: SyncConfiguration = SyncConfiguration.Builder(user, partitionValue, setOf()) .name(fileName) .build() - val suffix = "/mongodb-realm/${user.app.configuration.appId}/${user.identity}/$fileName" + val suffix = pathOf("", "mongodb-realm", user.app.configuration.appId, user.id, fileName) assertTrue(config.path.endsWith(suffix), "${config.path} failed.") assertEquals(fileName, config.name, "${config.name} failed.") } diff --git a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncedRealmTests.kt b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncedRealmTests.kt index 038d06c91d..d8c59a2b38 100644 --- a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncedRealmTests.kt +++ b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncedRealmTests.kt @@ -29,6 +29,7 @@ import io.realm.kotlin.entities.sync.flx.FlexEmbeddedObject import io.realm.kotlin.entities.sync.flx.FlexParentObject import io.realm.kotlin.ext.query import io.realm.kotlin.internal.platform.fileExists +import io.realm.kotlin.internal.platform.pathOf import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.log.LogLevel import io.realm.kotlin.mongodb.App @@ -548,18 +549,19 @@ class SyncedRealmTests { } } - // Currently no good way to delete synced Realms that has been opened. - // See https://github.com/realm/realm-core/issues/5542 + // Currently there isn't a good good way to delete synced Realms that has been opened, but + // `Sync.waitForSessionsToTerminate` can be used in some cases. + // + // See https://github.com/realm/realm-core/issues/5542 for more details @Test @Suppress("LongMethod") - @Ignore fun deleteRealm() { val fileSystem = FileSystem.SYSTEM val user = app.asTestApp.createUserAndLogin() val configuration: SyncConfiguration = SyncConfiguration.create(user, partitionValue, setOf()) val syncDir: Path = - "${app.configuration.syncRootDirectory}/mongodb-realm/${app.configuration.appId}/${user.identity}".toPath() + pathOf(app.configuration.syncRootDirectory, "mongodb-realm", app.configuration.appId, user.id).toPath() val bgThreadReadyChannel = Channel(1) val readyToCloseChannel = Channel(1) @@ -590,6 +592,7 @@ class SyncedRealmTests { closedChannel.receiveOrFail() // Delete realm now that it's fully closed. + app.sync.waitForSessionsToTerminate() Realm.deleteRealm(configuration) // Lock file should never be deleted.