blob: 98dfba554f822148a6f823a764125e3d3b6b0d38 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
library syncbase_batch_test;
import 'dart:async';
import 'dart:convert' show UTF8;
import 'package:test/test.dart';
import 'package:syncbase/syncbase_client.dart';
import './utils.dart' as utils;
Future<SyncbaseDatabase> setupDatabase(SyncbaseClient c) async {
var app = c.app(utils.uniqueName('app'));
await app.create(utils.emptyPerms());
var db = app.noSqlDatabase(utils.uniqueName('db'));
await db.create(utils.emptyPerms());
return db;
}
// TODO(sadovsky): Add more tests once we've decided which tests should exist in
// all client libraries.
runBatchTests(SyncbaseClient c) {
test('beginBatch creates a BatchDatabase with name', () async {
var db = await setupDatabase(c);
var batch = await db.beginBatch(SyncbaseClient.batchOptions());
expect(batch.name, equals(db.name));
expect(batch.fullName, isNot(equals(db.fullName)));
});
test('isolation', () async {
var db = await setupDatabase(c);
var tableName = 'tb';
var tb = db.table(tableName);
await tb.create(utils.emptyPerms());
// Table should start empty.
expect(await utils.scan(tb, ''), equals([]));
var batch1 = await db.beginBatch(SyncbaseClient.batchOptions());
var btb1 = batch1.table(tableName);
var batch2 = await db.beginBatch(SyncbaseClient.batchOptions());
var btb2 = batch2.table(tableName);
// Write some rows to each batch, with partial overlap.
var batch1Kvs = [new utils.KV('a', '1'), new utils.KV('b', '1')];
var batch2Kvs = [new utils.KV('a', '2'), new utils.KV('c', '2')];
await utils.putMany(btb1, batch1Kvs);
await utils.putMany(btb2, batch2Kvs);
// Each batch should only see the rows written to it.
expect(await utils.scan(btb1, ''), equals(batch1Kvs));
expect(await utils.scan(btb2, ''), equals(batch2Kvs));
// Table should still be empty since nothing has been committed.
expect(await utils.scan(tb, ''), equals([]));
// Commit batch1 and check that we see its rows in the non-batch table.
await batch1.commit();
expect(await utils.scan(tb, ''), equals(batch1Kvs));
// batch2 should still only see the rows written to it.
expect(await utils.scan(btb2, ''), equals(batch2Kvs));
// Committing batch2 should fail, and the table should still only contain
// batch1's records afterwards.
expect(batch2.commit(), throws);
expect(await utils.scan(tb, ''), equals(batch1Kvs));
});
test('runInBatch', () async {
var d = await setupDatabase(c);
var tableName = 'tb';
var tb = d.table(tableName);
await tb.create(utils.emptyPerms());
var retries = 0;
await runInBatch(d, SyncbaseClient.batchOptions(),
(SyncbaseBatchDatabase b) async {
++retries;
// Read foo. It does not exist.
expect(b.table(tableName).get("foo-${retries}"), throws);
// If we need to fail, write to foo in a separate concurrent batch. This
// is always written on every attempt.
if (retries < 2) {
await d.table(tableName).put("foo-${retries}", UTF8.encode('foo'));
}
// Write to bar.
await b.table(tableName).put("bar-${retries}", UTF8.encode('bar'));
});
// First try failed, second succeeded.
expect(retries, equals(2));
expect(await utils.scan(tb, ''),
equals([new utils.KV('bar-2', 'bar'), new utils.KV('foo-1', 'foo')]));
});
test('runInBatchReadOnly', () async {
var d = await setupDatabase(c);
var tableName = 'tb';
var tb = d.table(tableName);
await tb.create(utils.emptyPerms());
await d.table(tableName).put("foo", UTF8.encode('foo'));
var retries = 0;
await runInBatch(d, SyncbaseClient.batchOptions(readOnly: true),
(SyncbaseBatchDatabase b) async {
++retries;
// Read foo.
var before = await b.table(tableName).get("foo");
// Write to foo in a separate concurrent batch. This is always written
// on every iteration. It should not cause a retry since readonly
// batches are not committed.
await d.table(tableName).put("foo", UTF8.encode('oof'));
// Read foo again. Batch should not see the changed value.
expect(await b.table(tableName).get("foo"), equals(before));
// Try writing to bar. This should fail since the batch is readonly.
expect(b.table(tableName).put("bar", UTF8.encode('bar')), throws);
});
// Single uncommitted iteration.
expect(retries, equals(1));
expect(await utils.scan(tb, ''), equals([new utils.KV('foo', 'oof')]));
});
}