diff --git a/.github/workflows/binary-combine-android.yml b/.github/workflows/binary-combine-android.yml index d41d28c78..6187c54f9 100644 --- a/.github/workflows/binary-combine-android.yml +++ b/.github/workflows/binary-combine-android.yml @@ -9,11 +9,6 @@ jobs: timeout-minutes: 15 runs-on: ubuntu-latest steps: - - name: Fetch x86 build - uses: actions/download-artifact@v4 - with: - name: librealm-android-x86 - path: packages/realm_dart/binary/android - name: Fetch x86_64 build uses: actions/download-artifact@v4 with: @@ -41,7 +36,6 @@ jobs: uses: geekyeggo/delete-artifact@v4 with: name: | - librealm-android-x86 librealm-android-x86_64 librealm-android-armeabi-v7a librealm-android-arm64-v8a diff --git a/.github/workflows/build-native.yml b/.github/workflows/build-native.yml index 33c1a0341..67352f8ef 100644 --- a/.github/workflows/build-native.yml +++ b/.github/workflows/build-native.yml @@ -51,6 +51,10 @@ jobs: if: startsWith(matrix.build, 'android') run: echo "ANDROID_NDK=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV + - name: Downgrade XCode for MacOS + if: matrix.build == 'macos' + run: sudo xcodes select 14.3.1 + - name: Build if: steps.check-cache.outputs.cache-hit != 'true' run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d62f8661..f0b577f51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: with: runner: ubuntu-20.04 binary: android - build: '["android-x86", "android-x86_64", "android-armeabi-v7a", "android-arm64-v8a"]' + build: '["android-x86_64", "android-armeabi-v7a", "android-arm64-v8a"]' build-ios: name: Build IOS diff --git a/CHANGELOG.md b/CHANGELOG.md index a108d2c43..b17bd24cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,23 @@ ## vNext (TBD) ### Enhancements -* None +* Nested collections have full support for automatic client reset. (Core 14.7.0) ### Fixed * Private fields did not work with default values. (Issue [#1663](https://github.com/realm/realm-dart/issues/1663)) +* Having links in a nested collections would leave the file inconsistent if the top object is removed. (Core 14.7.0) + +* Accessing App.currentUser from within a notification produced by App.switchUser() (which includes notifications for a newly logged in user) would deadlock. (Core 14.7.0) + +* Inserting the same typed link to the same key in a dictionary more than once would incorrectly create multiple backlinks to the object. This did not appear to cause any crashes later, but would have affecting explicit backlink count queries (eg: `...@links.@count`) and possibly notifications. (Core 14.7.0) + + ### Compatibility * Realm Studio: 15.0.0 or later. ### Internal -* Using Core x.y.z. +* Using Core 14.7.0. ## 2.2.1 (2024-05-02) @@ -22,6 +29,7 @@ ### Internal * Using Core 14.6.2. +* Drop build of `x86` android slice. (Issue [#1670](https://github.com/realm/realm-dart/issues/1670)) ## 2.2.0 (2024-05-01) diff --git a/packages/realm_dart/CMakePresets.json b/packages/realm_dart/CMakePresets.json index a3ff6e63b..b83696281 100644 --- a/packages/realm_dart/CMakePresets.json +++ b/packages/realm_dart/CMakePresets.json @@ -87,14 +87,6 @@ "ANDROID_NDK_HOME": "$env{ANDROID_NDK}" } }, - { - "name": "android-x86", - "displayName": "Android x86", - "inherits": "android", - "cacheVariables": { - "CMAKE_ANDROID_ARCH_ABI": "x86" - } - }, { "name": "android-x86_64", "displayName": "Android x86_64", @@ -138,12 +130,6 @@ "displayName": "x64", "configuration": "Debug" }, - { - "name": "android-x86", - "configurePreset": "android-x86", - "displayName": "x86", - "configuration": "Debug" - }, { "name": "android-x86_64", "configurePreset": "android-x86_64", diff --git a/packages/realm_dart/dev/lib/src/build.dart b/packages/realm_dart/dev/lib/src/build.dart index 99a4b293a..e6659975a 100644 --- a/packages/realm_dart/dev/lib/src/build.dart +++ b/packages/realm_dart/dev/lib/src/build.dart @@ -68,7 +68,6 @@ enum OS { enum Target { androidArm(Architecture.arm, OS.android), androidArm64(Architecture.arm64, OS.android), - androidIA32(Architecture.ia32, OS.android), androidX64(Architecture.x64, OS.android), // only for emulator // androidRiscv64, // not supported by realm currently // fuchsiaArm64, // -"- etc. diff --git a/packages/realm_dart/scripts/build-android.sh b/packages/realm_dart/scripts/build-android.sh index e76d37ce7..41bd394c6 100755 --- a/packages/realm_dart/scripts/build-android.sh +++ b/packages/realm_dart/scripts/build-android.sh @@ -21,11 +21,11 @@ fi # Start in the root directory of the project. cd "$(dirname "$0")/.." -ABIS=(x86 x86_64 armeabi-v7a arm64-v8a) +ABIS=(x86_64 armeabi-v7a arm64-v8a) -# only building for x86 if no arguments +# only building for arm64-v8a if no arguments if [ $# -eq 0 ]; then - ABIS=(x86) + ABIS=arm64-v8a) fi for abi in "${ABIS[@]}"; do diff --git a/packages/realm_dart/src/realm-core b/packages/realm_dart/src/realm-core index 9cf7ef4ad..1f2a4c741 160000 --- a/packages/realm_dart/src/realm-core +++ b/packages/realm_dart/src/realm-core @@ -1 +1 @@ -Subproject commit 9cf7ef4ad8e2f4c7a519c9a395ca3d253bb87aa8 +Subproject commit 1f2a4c74112c1988b00a862d348e3f91200c5c4b diff --git a/packages/realm_dart/src/realm_dart.cpp b/packages/realm_dart/src/realm_dart.cpp index 0cf17a246..ba1418cf6 100644 --- a/packages/realm_dart/src/realm_dart.cpp +++ b/packages/realm_dart/src/realm_dart.cpp @@ -35,12 +35,6 @@ std::string cpuArch = "arm64"; #pragma message("Building arm64") #endif - -#if REALM_ARCHITECTURE_X86_32 -std::string cpuArch = "x86"; -#pragma message("Building x86") -#endif - #if REALM_ARCHITECTURE_X86_64 std::string cpuArch = "x86_64"; #pragma message("Building x64") diff --git a/packages/realm_dart/test/app_test.dart b/packages/realm_dart/test/app_test.dart index f2b9e0afb..b543c0946 100644 --- a/packages/realm_dart/test/app_test.dart +++ b/packages/realm_dart/test/app_test.dart @@ -184,13 +184,19 @@ void main() { await app.deleteUser(user); expect(user.state, UserState.removed); - await expectLater(() => loginWithRetry(app, Credentials.emailPassword(username, strongPassword)), throws("invalid username/password")); + await expectLater( + () => loginWithRetry(app, Credentials.emailPassword(username, strongPassword)), + throwsA(isA() + .having((e) => e.message, 'message', equals('unauthorized')) + .having((e) => e.statusCode, 'statusCode', 401) + .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), + ); }); baasTest('Call Atlas function that does not exist', (configuration) async { final app = App(configuration); final user = await app.logIn(Credentials.anonymous()); - await expectLater(user.functions.call('notExisitingFunction'), throws("function not found: 'notExisitingFunction'")); + await expectLater(user.functions.call('notExisitingFunction'), throws("function not found")); }); baasTest('Call Atlas function with no arguments', (configuration) async { diff --git a/packages/realm_dart/test/credentials_test.dart b/packages/realm_dart/test/credentials_test.dart index 359703800..b93508d67 100644 --- a/packages/realm_dart/test/credentials_test.dart +++ b/packages/realm_dart/test/credentials_test.dart @@ -148,7 +148,13 @@ void main() { await authProvider.registerUser(username, strongPassword); await authProvider.callResetPasswordFunction(username, newPassword, functionArgs: ['success']); await app.logIn(Credentials.emailPassword(username, newPassword)); - await expectLater(() => app.logIn(Credentials.emailPassword(username, strongPassword)), throws("invalid username/password")); + await expectLater( + app.logIn(Credentials.emailPassword(username, strongPassword)), + throwsA(isA() + .having((e) => e.message, 'message', equals('unauthorized')) + .having((e) => e.statusCode, 'statusCode', 401) + .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), + ); }, appName: AppName.autoConfirm); baasTest('Email/Password - call reset password function with no additional arguments', (configuration) async { @@ -157,12 +163,16 @@ void main() { const String newPassword = "!@#!DQXQWD!223eda"; final authProvider = EmailPasswordAuthProvider(app); await authProvider.registerUser(username, strongPassword); - await expectLater(() async { + await expectLater( // Calling this function with no additional arguments fails for the test // because of the specific implementation of resetFunc in the cloud. // resetFunc returns status 'fail' in case no other status is passed. - return await authProvider.callResetPasswordFunction(username, newPassword); - }, throws('failed to reset password for user "$username"')); + authProvider.callResetPasswordFunction(username, newPassword), + throwsA(isA() + .having((e) => e.message, 'message', contains('failed to reset password for user "$username"')) + .having((e) => e.statusCode, 'statusCode', 400) + .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), + ); }, appName: AppName.autoConfirm); /// JWT Payload data @@ -298,14 +308,26 @@ void main() { var token = "eyJraWQiOiIxIiwiYWxnIjoiUlMyNTYiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiI2MmYzOTY4ODhhZjg3MjBiMzczZmYwNmEiLCJlbWFpbCI6Indvbmdfc2lnbml0dXJlX2tleUByZWFsbS5pbyIsImlhdCI6MTY2MDE0MjIxNSwiZXhwIjo0ODEzNzQyMjE1LCJhdWQiOiJtb25nb2RiLmNvbSIsImlzcyI6Imh0dHBzOi8vcmVhbG0uaW8ifQ.Af--ZUCL_KC7lAhrD_d1lq91O7qVwu7GqXifwxKojkLCkbjmAER9K2Xa7BPO8xNstFeX8m9uBo4BCD5B6XmngSmyCj5OZWdiG5LTR_uhA3MnpqcV3Vu40K4Yx8XrjPuCL39xVPnEfPKLGz5TjEcMLa8xMPqo51byX0q3mR2eSS4w1A7c5TiTNuQ23_SCO8aK95SyXwuUmU4mH0iR4sHPtf64WyoAXkx8w5twXExzky1_h473CwtAERdMsBhwz1YzFKP0kxU31pg5SRciF5Ly66sK1fSPTMQPuVdS_wKvAYll8_trWnWS83M3_PWs4UxzOdjSpoK0uqhN-_IC38YOGg"; final credentials = Credentials.jwt(token); - await expectLater(() => app.logIn(credentials), throws("crypto/rsa: verification error")); + await expectLater( + () => app.logIn(credentials), + throwsA(isA() + .having((e) => e.message, 'message', equals('unauthorized')) + .having((e) => e.statusCode, 'statusCode', 401) + .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), + ); }); baasTest('Facebook credentials - invalid or expired token', (configuration) async { final app = App(configuration); final accessToken = 'invalid or expired token'; final credentials = Credentials.facebook(accessToken); - await expectLater(() => app.logIn(credentials), throws("error fetching info from OAuth2 provider")); + await expectLater( + app.logIn(credentials), + throwsA(isA() + .having((e) => e.message, 'message', equals('unauthorized')) + .having((e) => e.statusCode, 'statusCode', 401) + .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), + ); }); baasTest('Function credentials - wrong payload', (configuration) { diff --git a/packages/realm_dart/test/user_test.dart b/packages/realm_dart/test/user_test.dart index 47b6570ed..df21c1087 100644 --- a/packages/realm_dart/test/user_test.dart +++ b/packages/realm_dart/test/user_test.dart @@ -382,7 +382,7 @@ void main() { await expectLater( () => app.logIn(credentials), throwsA(isA() - .having((e) => e.message, 'message', contains('invalid API key')) + .having((e) => e.message, 'message', equals('unauthorized')) .having((e) => e.statusCode, 'statusCode', 401) .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); @@ -405,7 +405,7 @@ void main() { await expectLater( () => app.logIn(credentials), throwsA(isA() - .having((e) => e.message, 'message', contains('invalid API key')) + .having((e) => e.message, 'message', equals('unauthorized')) .having((e) => e.statusCode, 'statusCode', 401) .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); }); @@ -452,7 +452,7 @@ void main() { await expectLater( () async => await app.logIn(credentials), throwsA(isA() - .having((e) => e.message, 'message', 'invalid API key') + .having((e) => e.message, 'message', 'unauthorized') .having((e) => e.statusCode, 'statusCode', 401) .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); });