Skip to content

Commit

Permalink
Merge branch 'ct/bump-core-14.10.3' into ct/fix_sync_client_config
Browse files Browse the repository at this point in the history
  • Loading branch information
rorbech committed Jul 17, 2024
2 parents ff8b587 + 364999a commit 5f86678
Show file tree
Hide file tree
Showing 15 changed files with 80 additions and 41 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/include-static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
run: ./gradlew ktlintCheck

- name: Stash Ktlint results
if: always()
run: |
rm -rf /tmp/ktlint
rm -rf /tmp/detekt
Expand All @@ -50,6 +51,7 @@ jobs:
- name: Publish Ktlint results
uses: actions/upload-artifact@v4
if: always()
with:
name: Ktlint Analyzer report
path: /tmp/ktlint/*
Expand Down Expand Up @@ -85,7 +87,8 @@ jobs:
- name: Run Detekt
run: ./gradlew detekt

- name: Stash Detekt results
- name: Stash Detekt results
if: always()
run: |
rm -rf /tmp/detekt
mkdir /tmp/detekt
Expand All @@ -99,6 +102,7 @@ jobs:
- name: Publish Detekt results
uses: actions/upload-artifact@v4
if: always()
with:
name: Detekt Analyzer report
path: /tmp/detekt/*
Expand Down
14 changes: 10 additions & 4 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ jobs:
key: jni-linux-lib-${{ needs.check-cache.outputs.packages-sha }}

- name: Setup Java 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION }}
java-version: ${{ vars.VERSION_JAVA }}
Expand Down Expand Up @@ -473,7 +473,7 @@ jobs:
echo '#!/bin/bash\nccache clang++ "$@"%"' > /usr/local/bin/ccache-clang++
- name: Setup Android SDK
uses: android-actions/setup-android@v2
uses: android-actions/setup-android@v3

- name: Install NDK
run: sdkmanager --install "ndk;${{ env.NDK_VERSION }}"
Expand Down Expand Up @@ -547,7 +547,9 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION }}
java-version: ${{ vars.VERSION_JAVA }}
java-version: |
17
${{ vars.VERSION_JAVA }}
- name: Setup Gradle and task/dependency caching
uses: gradle/actions/setup-gradle@v3
Expand Down Expand Up @@ -602,9 +604,13 @@ jobs:
echo '#!/bin/bash\nccache clang++ "$@"%"' > /usr/local/bin/ccache-clang++
- name: Setup Android SDK
uses: android-actions/setup-android@v2
env:
JAVA_HOME: ${{ env.JAVA_HOME_17_X64 }}
uses: android-actions/setup-android@v3

- name: Install NDK
env:
JAVA_HOME: ${{ env.JAVA_HOME_17_X64 }}
run: sdkmanager --install "ndk;${{ env.NDK_VERSION }}"

- name: Build Android Base Test Apk
Expand Down
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
* Minimum R8: 8.0.34.

### Internal
* None.

* Updated to Realm Core 14.10.4 commit 4f83c590c4340dd7760d5f070e2e81613eb536aa.

## 2.1.0 (2024-07-12)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public open class UnrecoverableSyncException internal constructor(message: Strin
* Thrown when the type of sync used by the server does not match the one used by the client, i.e.
* the server and client disagrees whether to use Partition-based or Flexible Sync.
*/
@Suppress("DEPRECATION")
public class WrongSyncTypeException internal constructor(message: String) :
UnrecoverableSyncException(message)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import io.realm.kotlin.mongodb.exceptions.FunctionExecutionException
import io.realm.kotlin.mongodb.exceptions.InvalidCredentialsException
import io.realm.kotlin.mongodb.exceptions.ServiceException
import io.realm.kotlin.mongodb.exceptions.SyncException
import io.realm.kotlin.mongodb.exceptions.UnrecoverableSyncException
import io.realm.kotlin.mongodb.exceptions.UserAlreadyConfirmedException
import io.realm.kotlin.mongodb.exceptions.UserAlreadyExistsException
import io.realm.kotlin.mongodb.exceptions.UserNotFoundException
Expand Down Expand Up @@ -91,19 +90,26 @@ internal fun convertSyncError(syncError: SyncError): SyncException {
syncError.compensatingWrites,
syncError.isFatal
)

ErrorCode.RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED,
ErrorCode.RLM_ERR_SYNC_PROTOCOL_NEGOTIATION_FAILED,
ErrorCode.RLM_ERR_SYNC_PERMISSION_DENIED -> {
ErrorCode.RLM_ERR_SYNC_PERMISSION_DENIED,
-> {
// Permission denied errors should be unrecoverable according to Core, i.e. the
// client will disconnect sync and transition to the "inactive" state
UnrecoverableSyncException(message)
@Suppress("DEPRECATION") io.realm.kotlin.mongodb.exceptions.UnrecoverableSyncException(
message
)
}

else -> {
// An error happened we are not sure how to handle. Just report as a generic
// SyncException.
when (syncError.isFatal) {
false -> SyncException(message, syncError.isFatal)
true -> UnrecoverableSyncException(message)
true -> @Suppress("DEPRECATION") io.realm.kotlin.mongodb.exceptions.UnrecoverableSyncException(
message
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ internal open class SyncSessionImpl(
nativePointer,
error,
message,
true
false
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ actual object PlatformUtils {
}
SystemClock.sleep(5000) // 5 seconds to give the GC some time to process
}

actual fun copyFile(originPath: String, targetPath: String) {
File(originPath).copyTo(File(targetPath))
}
}

// Allocs as much garbage as we can. Pass maxSize = 0 to use all available memory in the process.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import kotlin.time.Duration
expect object PlatformUtils {
fun createTempDir(prefix: String = Utils.createRandomString(16), readOnly: Boolean = false): String
fun deleteTempDir(path: String)
fun copyFile(originPath: String, targetPath: String)
fun sleep(duration: Duration)
fun threadId(): ULong
fun triggerGC()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class EncryptionTests {
// Initialize an encrypted Realm
val encryptedConf = RealmConfiguration
.Builder(

schema = setOf(Sample::class)
)
.directory(tmpDir)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.realm.kotlin.test.platform

import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
Expand All @@ -41,6 +42,10 @@ actual object PlatformUtils {
return dir.absolutePathString()
}

actual fun copyFile(originPath: String, targetPath: String) {
File(originPath).copyTo(File(targetPath))
}

actual fun deleteTempDir(path: String) {
val rootPath: Path = Paths.get(path)
val pathsToDelete: List<Path> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,8 @@ actual object PlatformUtils {
actual fun triggerGC() {
GC.collect()
}

actual fun copyFile(originPath: String, targetPath: String) {
platform.Foundation.NSFileManager.defaultManager.copyItemAtPath(originPath, targetPath, null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,20 @@ class AppTests {

// Create a configuration pointing to the metadata Realm for that app
val metadataDir = "${app.configuration.syncRootDirectory}/mongodb-realm/${app.configuration.appId}/server-utility/metadata/"

// Workaround for https://github.com/realm/realm-core/issues/7876
// We cannot validate if the test app metadata realm is encrypted directly, as it is cached
// and subsequent access wont validate the encryption key. Copying the Realm allows to bypass
// the cache.
PlatformUtils.copyFile(metadataDir + "sync_metadata.realm", metadataDir + "copy_sync_metadata.realm")

val wrongKey = TestHelper.getRandomKey()
val config = RealmConfiguration
.Builder(setOf())
.name("sync_metadata.realm")
.name("copy_sync_metadata.realm")
.directory(metadataDir)
.encryptionKey(wrongKey)
.schemaVersion(7)
.build()
assertTrue(fileExists(config.path))

Expand Down Expand Up @@ -478,10 +486,18 @@ class AppTests {

// Create a configuration pointing to the metadata Realm for that app
val metadataDir = "${app.configuration.syncRootDirectory}/mongodb-realm/${app.configuration.appId}/server-utility/metadata/"

// Workaround for https://github.com/realm/realm-core/issues/7876
// We cannot validate if the test app metadata realm is encrypted directly, as it is cached
// and subsequent access wont validate the encryption key. Copying the Realm allows to bypass
// the cache.
PlatformUtils.copyFile(metadataDir + "sync_metadata.realm", metadataDir + "copy_sync_metadata.realm")

val config = RealmConfiguration
.Builder(setOf())
.name("sync_metadata.realm")
.name("copy_sync_metadata.realm")
.directory(metadataDir)
.schemaVersion(7)
.build()
assertTrue(fileExists(config.path))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ class FLXProgressListenerTests {
try {
val flow = realm.syncSession.progressAsFlow(Direction.UPLOAD, ProgressMode.INDEFINITELY)
val job = async {
withTimeout(10.seconds) {
withTimeout(30.seconds) {
flow.collect {
channel.trySend(true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import kotlin.reflect.KClass
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertIs
Expand Down Expand Up @@ -710,10 +711,8 @@ class SyncClientResetIntegrationTests {
exception: ClientResetRequiredException
) {
// Notify that this callback has been invoked
assertEquals(
"[Sync][AutoClientResetFailed(1028)] A fatal error occurred during client reset: 'User-provided callback failed'.",
exception.message
)
assertContains(exception.message!!, "User-provided callback failed")

assertIs<IllegalStateException>(exception.cause)
assertEquals(
"User exception",
Expand Down Expand Up @@ -788,10 +787,8 @@ class SyncClientResetIntegrationTests {
exception: ClientResetRequiredException
) {
// Notify that this callback has been invoked
assertEquals(
"[Sync][AutoClientResetFailed(1028)] A fatal error occurred during client reset: 'User-provided callback failed'.",
exception.message
)
assertContains(exception.message!!, "User-provided callback failed")

channel.trySendOrFail(ClientResetEvents.ON_MANUAL_RESET_FALLBACK)
}
}).build()
Expand Down Expand Up @@ -1080,7 +1077,7 @@ class SyncClientResetIntegrationTests {
assertNotNull(exception.originalFilePath)
assertFalse(fileExists(exception.recoveryFilePath))
assertTrue(fileExists(exception.originalFilePath))
assertTrue(exception.message!!.contains("Simulate Client Reset"))
assertContains(exception.message!!, "Simulate Client Reset")
}
}
channel.close()
Expand Down Expand Up @@ -1123,10 +1120,8 @@ class SyncClientResetIntegrationTests {
exception: ClientResetRequiredException
) {
// Notify that this callback has been invoked
assertEquals(
"[Sync][AutoClientResetFailed(1028)] A fatal error occurred during client reset: 'User-provided callback failed'.",
exception.message
)
assertContains(exception.message!!, "User-provided callback failed")

channel.trySendOrFail(ClientResetEvents.ON_MANUAL_RESET_FALLBACK)
}
}).build()
Expand Down Expand Up @@ -1193,11 +1188,8 @@ class SyncClientResetIntegrationTests {
// Validate that files have been moved after explicit reset
assertFalse(fileExists(originalFilePath))
assertTrue(fileExists(recoveryFilePath))

assertEquals(
"[Sync][AutoClientResetFailed(1028)] A fatal error occurred during client reset: 'User-provided callback failed'.",
exception.message
)
println(exception.message)
assertContains(exception.message!!, "User-provided callback failed")

channel.trySendOrFail(ClientResetEvents.ON_MANUAL_RESET_FALLBACK)
}
Expand Down Expand Up @@ -1400,10 +1392,7 @@ class SyncClientResetIntegrationTests {
assertFalse(fileExists(originalFilePath))
assertTrue(fileExists(recoveryFilePath))

assertEquals(
"[Sync][AutoClientResetFailed(1028)] A fatal error occurred during client reset: 'User-provided callback failed'.",
exception.message
)
assertTrue(exception.message!!.contains("User-provided callback failed"))

channel.trySendOrFail(ClientResetEvents.ON_MANUAL_RESET_FALLBACK)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,14 +350,14 @@ class SyncedRealmTests {
syncSession = (realm.syncSession as SyncSessionImpl).nativePointer,
error = ErrorCode.RLM_ERR_ACCOUNT_NAME_IN_USE,
errorMessage = "Non fatal error",
isFatal = true, // flipped https://jira.mongodb.org/browse/RCORE-2146
isFatal = false,
)

RealmInterop.realm_sync_session_handle_error_for_testing(
syncSession = (realm.syncSession as SyncSessionImpl).nativePointer,
error = ErrorCode.RLM_ERR_INTERNAL_SERVER_ERROR,
errorMessage = "Fatal error",
isFatal = false, // flipped https://jira.mongodb.org/browse/RCORE-2146
isFatal = true,
)
}
}
Expand Down Expand Up @@ -1650,14 +1650,17 @@ class SyncedRealmTests {
println("Partition based sync bundled realm is in ${config2.path}")
}

// This test cannot run multiple times on the same server instance as the primary
// key of the objects from asset-pbs.realm will not be unique on secondary runs.
@Test
fun initialRealm_partitionBasedSync() {
val (email, password) = randomEmail() to "password1234"
val user = runBlocking {
app.createUserAndLogIn(email, password)
}

runBlocking {
app.asTestApp.deleteDocuments(app.configuration.appId, "ParentPk", "{}")
}

val config1 = createPartitionSyncConfig(
user = user, partitionValue = partitionValue, name = "db1",
errorHandler = object : SyncSession.ErrorHandler {
Expand Down

0 comments on commit 5f86678

Please sign in to comment.