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

Fix for updated flexible sync error message #4611

Merged
merged 6 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 6 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
x.x.x Release notes (yyyy-MM-dd)
=============================================================
### Enhancements
* None.
* Creating an object for a class that has no subscriptions opened for it will throw an exception. ([realm/realm-core#5488](https://github.com/realm/realm-core/pull/5488))

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?)
* Add canonical schema type for returned schemas ([#4580](https://github.com/realm/realm-js/pull/4580))
* Fixed invalid type for schema properties([#4577](https://github.com/realm/realm-js/pull/4577)).
* Add canonical schema type for returned schemas. ([#4580](https://github.com/realm/realm-js/pull/4580))
* Fixed invalid type for schema properties. ([#4577](https://github.com/realm/realm-js/pull/4577))
* FLX sync subscription state changes will now correctly be reported after sync progress is reported. ([realm/realm-core#5553](https://github.com/realm/realm-core/pull/5553), since v10.18.0)

### Compatibility
* MongoDB Realm Cloud.
Expand All @@ -15,6 +15,8 @@ x.x.x Release notes (yyyy-MM-dd)
* File format: generates Realms with format v22 (reads and upgrades file format v5 or later for non-synced Realm, upgrades file format v10 or later for synced Realms).

### Internal
* Upgraded Realm Core from v12.0.0 to v12.1.0.
* Fix for updated FLX sync error message. ([#4611](https://github.com/realm/realm-js/pull/4611))
* Updated build script to use Xcode 13.1 to match latest Apple App Store compatibility. ([#4605](https://github.com/realm/realm-js/issues/4605))

10.18.0 Release notes (2022-5-29)
Expand Down
18 changes: 9 additions & 9 deletions integration-tests/tests/src/tests/sync/flexible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ import Realm, { BSON, ClientResetMode, FlexibleSyncConfiguration, SessionStopPol

import { authenticateUserBefore, importAppBefore, openRealmBeforeEach } from "../../hooks";
import { DogSchema, IPerson, PersonSchema } from "../../schemas/person-and-dog-with-object-ids";
import { expectClientResetError } from "../../utils/expect-sync-error";
import { closeAndReopenRealm, closeRealm, closeThisRealm } from "../../utils/close-realm";
import { expectInvalidWriteSyncError } from "../../utils/expect-sync-error";
import { closeAndReopenRealm, closeRealm } from "../../utils/close-realm";

const FlexiblePersonSchema = { ...PersonSchema, properties: { ...PersonSchema.properties, nonQueryable: "string?" } };

Expand Down Expand Up @@ -1568,9 +1568,9 @@ describe.skipIf(environment.missingServer, "Flexible sync", function () {

// TODO test more complex integration scenarios, e.g. links, embedded objects, collections, complex queries

describe("client reset scenarios", function () {
it("triggers a client reset if items are added without a subscription", async function (this: RealmContext) {
await expectClientResetError(this.config, this.user, (realm) => {
describe("error scenarios", function () {
it("triggers an error if items are added without a subscription", async function (this: RealmContext) {
await expectInvalidWriteSyncError(this.config, this.user, (realm) => {
realm.write(() => {
return realm.create<IPerson>(FlexiblePersonSchema.name, {
_id: new BSON.ObjectId(),
Expand All @@ -1581,10 +1581,10 @@ describe.skipIf(environment.missingServer, "Flexible sync", function () {
});
});

it("triggers a client reset and deletes the item if an item not matching the filter is created", async function (this: RealmContext) {
it("triggers an error and deletes the item if an item not matching the filter is created", async function (this: RealmContext) {
await addSubscriptionAndSync(this.realm, this.realm.objects(FlexiblePersonSchema.name).filtered("age < 30"));

await expectClientResetError(
await expectInvalidWriteSyncError(
this.config,
this.user,
(realm) => {
Expand All @@ -1602,8 +1602,8 @@ describe.skipIf(environment.missingServer, "Flexible sync", function () {
);
});

it("triggers a client reset if you remove a subscription without waiting for server acknowledgement, then modify objects that were only matched by the now removed subscription", async function (this: RealmContext) {
await expectClientResetError(this.config, this.user, async (realm) => {
it("triggers an error if you remove a subscription without waiting for server acknowledgement, then modify objects that were only matched by the now removed subscription", async function (this: RealmContext) {
await expectInvalidWriteSyncError(this.config, this.user, async (realm) => {
const { sub } = await addSubscriptionForPersonAndSync(this.realm);

this.realm.subscriptions.update((mutableSubs) => {
Expand Down
3 changes: 2 additions & 1 deletion integration-tests/tests/src/tests/sync/mixed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function describeRoundtrip({

async function setupTest(realm: Realm) {
if (flexibleSync) {
realm.subscriptions.update((mutableSubs) => {
await realm.subscriptions.update((mutableSubs) => {
mutableSubs.add(realm.objects("MixedClass"));
});
await realm.subscriptions.waitForSynchronization();
Expand All @@ -94,6 +94,7 @@ function describeRoundtrip({
});

it("writes", async function (this: RealmContext) {
this.timeout(6000);
await setupTest(this.realm);

this._id = new Realm.BSON.ObjectId();
Expand Down
70 changes: 51 additions & 19 deletions integration-tests/tests/src/utils/expect-sync-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import { expect } from "chai";
import { openRealm } from "./open-realm";

type Error = Realm.SyncError | (Realm.ClientResetError & { message: string });

/**
* Open a new Realm and perform an action, expecting a sync error to occur. Will
* never resolve and therefore timeout if a sync error does not occur.
Expand All @@ -34,28 +36,58 @@ export async function expectSyncError(
config: Realm.Configuration,
user: Realm.User,
action: (realm: Realm) => void,
expectation: (error: Realm.SyncError | Realm.ClientResetError) => void,
expectation: (error: Error) => void,
): Promise<void> {
let handleError: Realm.ErrorCallback | undefined;

const configWithErrorHandler = { ...config };
if (!configWithErrorHandler.sync) {
throw new Error("Expected a sync config");
}

configWithErrorHandler.sync.error = (session, error) => {
if (handleError) handleError(session, error);
};
return new Promise((resolve, reject) => {
if (!config.sync) {
throw new Error("Expected a sync config");
}

const { realm } = await openRealm(configWithErrorHandler, user);

return new Promise((resolve) => {
handleError = (session, error) => {
expectation(error);
resolve();
// Shallow copy the sync configuration to modifying the original
const modifiedConfig: Realm.Configuration = {
...config,
sync: {
...config.sync,
error(_, error: Error) {
try {
expectation(error);
resolve();
} catch (err) {
reject(err);
}
},
},
};

action(realm);
openRealm(modifiedConfig, user).then(({ realm }) => action(realm), reject);
});
}

/**
* Expect a sync error to occur with a message about an invalid write.
* Optionally specify more expectations about the sync error. Will
* never resolve and therefore timeout if a sync error does not occur.
*
* @param config The Realm config to use
* @param user The Realm user to use
* @param action Callback receiving a Realm instance and containing the
* action(s) to take which should trigger a client reset error
* @param extraExpectation Optional callback receiving the sync error, in order to make more
* assertions about it
* @returns Promise which resolves if the sync error occurs
*/
export async function expectInvalidWriteSyncError(
config: Realm.Configuration,
user: Realm.User,
action: (realm: Realm) => void,
extraExpectation?: (error: Error) => void,
): Promise<void> {
return expectSyncError(config, user, action, (error) => {
expect(error.name).to.equal("Error");
expect(error.message).to.match(
/Client attempted a write that is outside of permissions or query filters; it has been reverted.*/,
);
if (extraExpectation) extraExpectation(error);
});
}

Expand All @@ -76,7 +108,7 @@ export async function expectClientResetError(
config: Realm.Configuration,
user: Realm.User,
action: (realm: Realm) => void,
extraExpectation?: (error: Realm.SyncError | Realm.ClientResetError) => void,
extraExpectation?: (error: Error) => void,
): Promise<void> {
return expectSyncError(config, user, action, (error) => {
expect(error.name).to.equal("ClientReset");
Expand Down
2 changes: 1 addition & 1 deletion vendor/realm-core
Submodule realm-core updated 91 files
+27 −1 CHANGELOG.md
+3 −3 Jenkinsfile
+9 −343 Package.swift
+2 −2 dependencies.list
+7 −6 doc/changeset.md
+56 −6 evergreen/config.yml
+48 −15 evergreen/install_baas.sh
+3 −3 how-to-build.md
+28 −19 src/realm.h
+6 −1 src/realm/cluster.cpp
+16 −10 src/realm/db.cpp
+6 −9 src/realm/db.hpp
+10 −0 src/realm/exceptions.hpp
+5 −1 src/realm/exec/realm_trawler.cpp
+30 −7 src/realm/group.cpp
+34 −24 src/realm/group.hpp
+5 −10 src/realm/impl/copy_replication.cpp
+3 −3 src/realm/impl/copy_replication.hpp
+1 −0 src/realm/list.cpp
+1 −3 src/realm/mixed.hpp
+8 −0 src/realm/obj.cpp
+10 −11 src/realm/object-store/c_api/notifications.cpp
+6 −5 src/realm/object-store/c_api/sync.cpp
+16 −1 src/realm/object-store/c_api/types.hpp
+25 −0 src/realm/object-store/impl/realm_coordinator.cpp
+11 −1 src/realm/object-store/object_accessor.hpp
+41 −2 src/realm/object-store/object_schema.cpp
+6 −0 src/realm/object-store/object_schema.hpp
+23 −5 src/realm/object-store/object_store.cpp
+33 −27 src/realm/object-store/sync/sync_session.cpp
+1 −1 src/realm/object-store/sync/sync_session.hpp
+7 −1 src/realm/object-store/sync/sync_user.hpp
+1 −1 src/realm/parser/CMakeLists.txt
+7 −0 src/realm/query.cpp
+4 −2 src/realm/replication.cpp
+6 −6 src/realm/replication.hpp
+3 −1 src/realm/set.cpp
+8 −7 src/realm/sync/changeset.cpp
+17 −5 src/realm/sync/changeset_encoder.cpp
+135 −77 src/realm/sync/changeset_parser.cpp
+19 −10 src/realm/sync/changeset_parser.hpp
+7 −13 src/realm/sync/client.cpp
+2 −2 src/realm/sync/client_base.hpp
+5 −1 src/realm/sync/config.cpp
+6 −1 src/realm/sync/config.hpp
+14 −13 src/realm/sync/instruction_applier.cpp
+30 −21 src/realm/sync/instruction_replication.cpp
+14 −2 src/realm/sync/instruction_replication.hpp
+9 −7 src/realm/sync/instructions.hpp
+9 −0 src/realm/sync/noinst/client_history_impl.cpp
+30 −17 src/realm/sync/noinst/client_history_impl.hpp
+37 −19 src/realm/sync/noinst/client_impl_base.cpp
+6 −4 src/realm/sync/noinst/client_impl_base.hpp
+3 −2 src/realm/sync/noinst/client_reset.cpp
+39 −5 src/realm/sync/noinst/protocol_codec.hpp
+1 −1 src/realm/sync/noinst/sync_metadata_schema.cpp
+4 −0 src/realm/sync/protocol.cpp
+39 −4 src/realm/sync/protocol.hpp
+33 −12 src/realm/sync/subscriptions.cpp
+12 −2 src/realm/sync/subscriptions.hpp
+14 −8 src/realm/sync/transform.cpp
+72 −25 src/realm/table.cpp
+45 −9 src/realm/table.hpp
+2 −2 src/realm/util/compression.cpp
+ test/downgrade_asymmetric.realm
+6 −1 test/object-store/CMakeLists.txt
+6 −0 test/object-store/audit.cpp
+17 −12 test/object-store/c_api/c_api.cpp
+81 −0 test/object-store/object.cpp
+56 −2 test/object-store/schema.cpp
+399 −34 test/object-store/sync/flx_sync.cpp
+5 −0 test/object-store/sync/flx_sync_harness.hpp
+1 −1 test/object-store/sync/sync_test_utils.cpp
+61 −21 test/object-store/util/baas_admin_api.cpp
+10 −0 test/object-store/util/baas_admin_api.hpp
+18 −1 test/test_changeset_encoding.cpp
+13 −13 test/test_embedded_objects.cpp
+14 −14 test/test_group.cpp
+1 −1 test/test_instruction_replication.cpp
+2 −2 test/test_json.cpp
+2 −2 test/test_lang_bind_helper.cpp
+4 −2 test/test_links.cpp
+10 −0 test/test_query.cpp
+11 −11 test/test_shared.cpp
+1 −1 test/test_sync.cpp
+44 −0 test/test_sync_subscriptions.cpp
+36 −7 test/test_table.cpp
+4 −4 test/test_transform.cpp
+32 −0 test/test_typed_links.cpp
+1 −1 test/test_unresolved_links.cpp
+17 −0 test/test_upgrade_database.cpp