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

Throws last core error when beginWriteAsync and commitWriteAsync #974

Merged
merged 14 commits into from
Dec 12, 2022
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Breaking Changes
* File format version bumped.
* The layout of the lock-file has changed, the lock file format version is bumped and all participants in a multiprocess scenario needs to be up to date so they expect the same format. This requires an update of Studio. (Core upgrade)
* Writing to a frozen realm throws `RealmException` instead of `RealmError`. ([#974](https://github.com/realm/realm-dart/pull/974))

### Enhancements
* Support setting `maxNumberOfActiveVersions` when creating a `Configuration`. ([#1036](https://github.com/realm/realm-dart/pull/1036))
Expand All @@ -21,6 +22,7 @@
* Removed the ".tmp_compaction_space" file being left over after compacting a Realm on Windows. (Core upgrade).
* Restore fallback to full barrier when F_BARRIERSYNC is not available on Apple platforms. (Core upgrade, since v0.8.0+rc)
* Fixed wrong assertion on query error that could result in a crash. (Core upgrade)
* Writing to a read-only realm throws `RealmException` instead of blocking the isolate. ([#974](https://github.com/realm/realm-dart/pull/974))

### Compatibility
* Realm Studio: 13.0.0 or later.
Expand Down
12 changes: 0 additions & 12 deletions lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -321,20 +321,14 @@ class Realm implements Finalizable {

/// Begins a write transaction for this [Realm].
Transaction beginWrite() {
_ensureWritable();

realmCore.beginWrite(this);

return Transaction._(this);
}

/// Asynchronously begins a write transaction for this [Realm]. You can supply a
/// [CancellationToken] to cancel the operation.
Future<Transaction> beginWriteAsync([CancellationToken? cancellationToken]) async {
_ensureWritable();

await realmCore.beginWriteAsync(this, cancellationToken);

return Transaction._(this);
}

Expand Down Expand Up @@ -496,12 +490,6 @@ class Realm implements Finalizable {
}
}

void _ensureWritable() {
blagoev marked this conversation as resolved.
Show resolved Hide resolved
if (isFrozen) {
throw RealmError('Starting a write transaction on a frozen Realm is not allowed.');
}
}

/// Compacts a Realm file. A Realm file usually contains free/unused space.
///
/// This method removes this free space and the file size is thereby reduced.
Expand Down
10 changes: 0 additions & 10 deletions test/configuration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,6 @@ Future<void> main([List<String>? args]) async {
expect(cars.length, 1);
});

test('Configuration readOnly - writing on read-only Realms throws', () {
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
Configuration config = Configuration.local([Car.schema]);
var realm = getRealm(config);
realm.close();

config = Configuration.local([Car.schema], isReadOnly: true);
realm = getRealm(config);
expect(() => realm.write(() {}), throws<RealmException>("Can't perform transactions on read-only Realms."));
});

test('Configuration inMemory - no files after closing realm', () {
Configuration config = Configuration.inMemory([Car.schema]);
var realm = getRealm(config);
Expand Down
72 changes: 33 additions & 39 deletions test/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,26 @@ Future<void> main([List<String>? args]) async {
expect(realm.write(() => realm.add(carTwo, update: true)), carTwo);
});

test('Realm write after realm is closed', () {
test('Realm write after realm is closed', () async {
var config = Configuration.local([Car.schema]);
var realm = getRealm(config);

final car = Car('Tesla');

realm.close();
expect(() => realm.write(() {}), throws<RealmClosedError>("Cannot access realm that has been closed"));
_expectAllWritesToThrow<RealmClosedError>(realm, "Cannot access realm that has been closed");
_expectAllAsyncWritesToThrow<RealmClosedError>(realm, "Cannot access realm that has been closed");
});

test('Realm write on read-only realms throws', () async {
Configuration config = Configuration.local([Car.schema]);
var realm = getRealm(config);
realm.close();

config = Configuration.local([Car.schema], isReadOnly: true);
realm = getRealm(config);
_expectAllWritesToThrow<RealmException>(realm, "Can't perform transactions on read-only Realms.");
_expectAllAsyncWritesToThrow<RealmException>(realm, "Can't perform transactions on read-only Realms.");
});

test('Realm query', () {
Expand Down Expand Up @@ -581,7 +593,7 @@ Future<void> main([List<String>? args]) async {
final realm = getRealm(config);
realm.write(() {
// Second write inside the first one fails but the error is caught
expect(() => realm.write(() {}), throws<RealmException>('The Realm is already in a write transaction'));
_expectAllWritesToThrow<RealmException>(realm, "The Realm is already in a write transaction");
});
});

Expand Down Expand Up @@ -719,36 +731,13 @@ Future<void> main([List<String>? args]) async {
expect(realm.all<Person>().length, 0);
});

test('FrozenRealm cannot write', () {
final config = Configuration.local([Person.schema]);
final realm = getRealm(config);

final frozenRealm = freezeRealm(realm);
expect(() => frozenRealm.write(() {}), throws<RealmError>("Starting a write transaction on a frozen Realm is not allowed."));
});

test('FrozenRealm cannot beginWrite', () {
final config = Configuration.local([Person.schema]);
final realm = getRealm(config);

final frozenRealm = freezeRealm(realm);
expect(() => frozenRealm.beginWrite(), throws<RealmError>("Starting a write transaction on a frozen Realm is not allowed."));
});

test('FrozenRealm cannot writeAsync', () async {
test('FrozenRealm cannot write', () async {
final config = Configuration.local([Person.schema]);
final realm = getRealm(config);

final frozenRealm = freezeRealm(realm);
await expectLater(() => frozenRealm.writeAsync(() {}), throws<RealmError>("Starting a write transaction on a frozen Realm is not allowed."));
});

test('FrozenRealm cannot beginWriteAsync', () async {
final config = Configuration.local([Person.schema]);
final realm = getRealm(config);

final frozenRealm = freezeRealm(realm);
await expectLater(() => frozenRealm.beginWriteAsync(), throws<RealmError>("Starting a write transaction on a frozen Realm is not allowed."));
_expectAllWritesToThrow<RealmException>(frozenRealm, "Can't perform transactions on a frozen Realm");
_expectAllAsyncWritesToThrow<RealmException>(frozenRealm, "Can't perform transactions on a frozen Realm");
});

test('realm.freeze when frozen returns the same instance', () {
Expand Down Expand Up @@ -1018,7 +1007,6 @@ Future<void> main([List<String>? args]) async {
test('Realm.beginWriteAsync starts write transaction', () async {
final realm = getRealm(Configuration.local([Person.schema]));
final transaction = await realm.beginWriteAsync();

expect(transaction.isOpen, true);
});

Expand All @@ -1027,7 +1015,6 @@ Future<void> main([List<String>? args]) async {
final transaction = await realm.beginWriteAsync();
realm.add(Person('John'));
transaction.commit();

expect(realm.all<Person>().length, 1);
});

Expand All @@ -1036,7 +1023,6 @@ Future<void> main([List<String>? args]) async {
final transaction = await realm.beginWriteAsync();
realm.add(Person('John'));
await transaction.commitAsync();

expect(realm.all<Person>().length, 1);
});

Expand All @@ -1054,7 +1040,6 @@ Future<void> main([List<String>? args]) async {
final transaction = realm.beginWrite();
realm.add(Person('John'));
await transaction.commitAsync();

expect(realm.all<Person>().length, 1);
});

Expand Down Expand Up @@ -1416,7 +1401,7 @@ Future<void> main([List<String>? args]) async {

Future<int> createRealmForCompact(Configuration config) async {
var realm = getRealm(config);

if (config is FlexibleSyncConfiguration) {
realm.subscriptions.update((mutableSubscriptions) {
mutableSubscriptions.add(realm.query<Product>("stringQueryField CONTAINS '$compactTest'"));
Expand All @@ -1425,7 +1410,7 @@ Future<void> main([List<String>? args]) async {
}

addDataForCompact(realm);

if (config is FlexibleSyncConfiguration) {
await realm.syncSession.waitForDownload();
await realm.syncSession.waitForUpload();
Expand All @@ -1439,7 +1424,7 @@ Future<void> main([List<String>? args]) async {

void validateCompact(bool compacted, String realmPath, int beforeCompactSizeSize) async {
expect(compacted, true);
final afterCompactSize = await File(realmPath).stat().then((value) => value.size);
final afterCompactSize = await File(realmPath).stat().then((value) => value.size);
expect(beforeCompactSizeSize, greaterThan(afterCompactSize));
}

Expand All @@ -1455,7 +1440,7 @@ Future<void> main([List<String>? args]) async {
final realm = getRealm(config);
});

test('Realm - non existing realm can not be compacted', () async {
test('Realm - non existing realm can not be compacted', () async {
var config = Configuration.local([Product.schema], path: p.join(Configuration.defaultStoragePath, "${generateRandomString(8)}.realm"));
final compacted = Realm.compact(config);
expect(compacted, false);
Expand Down Expand Up @@ -1553,8 +1538,7 @@ Future<void> main([List<String>? args]) async {
final path = p.join(Configuration.defaultStoragePath, "${generateRandomString(8)}.realm");
var user = await app.logIn(credentials);
List<int> key = List<int>.generate(encryptionKeySize, (i) => random.nextInt(256));
final config =
Configuration.flexibleSync(user, [Product.schema], encryptionKey: key, path: path);
final config = Configuration.flexibleSync(user, [Product.schema], encryptionKey: key, path: path);
final beforeCompactSize = await createRealmForCompact(config);
user.logOut();
Future<void>.delayed(Duration(seconds: 5));
Expand Down Expand Up @@ -1647,3 +1631,13 @@ When newWhen([tz.TZDateTime? time]) {
extension _IterableEx<T> on Iterable<T> {
Iterable<T> except(T exclude) => where((o) => o != exclude);
}

void _expectAllWritesToThrow<T>(Realm realm, String exceptionMessage) {
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
expect(() => realm.write(() {}), throws<T>(exceptionMessage));
expect(() => realm.beginWrite(), throws<T>(exceptionMessage));
}

void _expectAllAsyncWritesToThrow<T>(Realm realm, String exceptionMessage) {
expect(() => realm.writeAsync(() {}), throws<T>(exceptionMessage));
expect(() => realm.beginWriteAsync(), throws<T>(exceptionMessage));
}
2 changes: 1 addition & 1 deletion test/test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ Future<void> tryDeleteRealm(String path) async {
for (var i = 0; i < 5; i++) {
try {
Realm.deleteRealm(path);

//delete lock file
await File('$path.lock').delete().onError((error, stackTrace) => dummy);

Expand Down