syncbase: Start of client tests.
Tests for naming, creation, deletion, and existence for App, Database,
Table, and Row objects.
Change-Id: I840457414d4be3d6218a10d66d0316b25f7005b4
diff --git a/dart/lib/src/app.dart b/dart/lib/src/app.dart
index 53d254e..f47cfdf 100644
--- a/dart/lib/src/app.dart
+++ b/dart/lib/src/app.dart
@@ -2,7 +2,7 @@
class SyncbaseApp extends NamedResource {
SyncbaseApp._internal(_proxy, fullName)
- : super._internal(_proxy, '', fullName);
+ : super._internal(_proxy, null, fullName);
// noSqlDatabase returns the noSqlDatabase with the given relativeName.
// relativeName must not contain slashes.
diff --git a/dart/lib/src/named_resource.dart b/dart/lib/src/named_resource.dart
index 85f750e..9b51356 100644
--- a/dart/lib/src/named_resource.dart
+++ b/dart/lib/src/named_resource.dart
@@ -2,16 +2,16 @@
// NamedResource is the superclass of resources with names.
class NamedResource {
- final String _parentFullName;
final String fullName;
final String relativeName;
final mojom.SyncbaseProxy _proxy;
- NamedResource._internal(_proxy, _parentFullName, relativeName)
+ NamedResource._internal(
+ mojom.SyncbaseProxy _proxy, String _parentFullName, String relativeName)
: this._proxy = _proxy,
- this._parentFullName = _parentFullName,
this.relativeName = relativeName,
- this.fullName = _parentFullName + '/' + relativeName {
+ this.fullName = (_parentFullName == null ? '' : _parentFullName + '/') +
+ relativeName {
if (relativeName.contains('/')) {
throw 'relativeName cannot contain "/": $relativeName';
}
diff --git a/dart/lib/src/nosql/row.dart b/dart/lib/src/nosql/row.dart
index fb1f034..2968eb6 100644
--- a/dart/lib/src/nosql/row.dart
+++ b/dart/lib/src/nosql/row.dart
@@ -10,13 +10,13 @@
return v.exists;
}
- Future<Uint8List> get() async {
+ Future<List<int>> get() async {
var v = await _proxy.ptr.rowGet(fullName);
if (isError(v.err)) throw v.err;
return v.value;
}
- Future put(Uint8List value) async {
+ Future put(List<int> value) async {
var v = await _proxy.ptr.rowPut(fullName, value);
if (isError(v.err)) throw v.err;
return;
diff --git a/dart/lib/src/nosql/table.dart b/dart/lib/src/nosql/table.dart
index 78ca108..5bdbd0f 100644
--- a/dart/lib/src/nosql/table.dart
+++ b/dart/lib/src/nosql/table.dart
@@ -26,13 +26,13 @@
return v.exists;
}
- Future deleteRowRange(Uint8List start, Uint8List limit) async {
+ Future deleteRowRange(List<int> start, List<int> limit) async {
var v = await _proxy.ptr.tableDeleteRowRange(fullName, start, limit);
if (isError(v.err)) throw v.err;
return;
}
- Stream<mojom.KeyValue> scan(Uint8List start, Uint8List limit) {
+ Stream<mojom.KeyValue> scan(List<int> start, List<int> limit) {
StreamController<mojom.KeyValue> sc = new StreamController();
mojom.ScanStream scanStream = new ScanStreamImpl._fromStreamController(sc);
diff --git a/dart/lib/syncbase_client.dart b/dart/lib/syncbase_client.dart
index f61c628..3d48c41 100644
--- a/dart/lib/syncbase_client.dart
+++ b/dart/lib/syncbase_client.dart
@@ -1,13 +1,15 @@
library syncbase_client;
import 'dart:async';
-import 'dart:typed_data' show Uint8List;
import 'package:mojo/application.dart' show Application;
import 'gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart' as mojom;
// Export struct types from syncbase.mojom.
+// TODO(nlacasse): Create wrapper around Perms, and possibly other struct
+// constructors, since the default constructors are not user-friendly. They
+// take zero arguments, so all fields must be populated with assignments.
export 'gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart'
show BatchOptions, Perms, SyncGroupMemberInfo, SyncGroupSpec;
@@ -22,9 +24,6 @@
return err != null && err.id != '';
}
-// TODO(nlacasse): Write some tests for this interface now that syncbase runs
-// as a mojo service. Currently we rely on dartanalyzer for correctness.
-
class SyncbaseClient {
final Application _mojoApp;
final mojom.SyncbaseProxy _proxy;
diff --git a/dart/test/syncbase_app_test.dart b/dart/test/syncbase_app_test.dart
new file mode 100644
index 0000000..97ef1e5
--- /dev/null
+++ b/dart/test/syncbase_app_test.dart
@@ -0,0 +1,29 @@
+library syncbase_app_test;
+
+import 'package:test/test.dart';
+
+import 'package:ether/syncbase_client.dart' show SyncbaseClient;
+
+import './utils.dart' as utils;
+
+runAppTests(SyncbaseClient c) {
+ test('getting a handle to an app', () {
+ var appName = utils.uniqueName('app');
+ var app = c.app(appName);
+ expect(app.relativeName, equals(appName));
+ expect(app.fullName, equals(appName));
+ });
+
+ test('creating and deleting an app', () async {
+ var appName = utils.uniqueName('app');
+ var app = c.app(appName);
+
+ expect(await app.exists(), equals(false));
+ await app.create(utils.emptyPerms());
+ expect(await app.exists(), equals(true));
+ await app.delete();
+ expect(await app.exists(), equals(false));
+ });
+
+ // TODO(nlacasse): Test app.get/setPermissions.
+}
diff --git a/dart/test/syncbase_database_test.dart b/dart/test/syncbase_database_test.dart
new file mode 100644
index 0000000..dd81c0f
--- /dev/null
+++ b/dart/test/syncbase_database_test.dart
@@ -0,0 +1,32 @@
+library syncbase_database_test;
+
+import 'package:test/test.dart';
+
+import 'package:ether/syncbase_client.dart' show SyncbaseClient;
+
+import './utils.dart' as utils;
+
+runDatabaseTests(SyncbaseClient c) {
+ test('getting a handle to a database', () {
+ var app = c.app(utils.uniqueName('app'));
+ var dbName = utils.uniqueName('db');
+ var db = app.noSqlDatabase(dbName);
+ expect(db.relativeName, equals(dbName));
+ expect(db.fullName, equals(app.fullName + '/' + dbName));
+ });
+
+ test('creating and deleting a database', () async {
+ var app = c.app(utils.uniqueName('app'));
+ await app.create(utils.emptyPerms());
+
+ var db = app.noSqlDatabase(utils.uniqueName('db'));
+
+ expect(await db.exists(), equals(false));
+ await db.create(utils.emptyPerms());
+ expect(await db.exists(), equals(true));
+ await db.delete();
+ expect(await db.exists(), equals(false));
+ });
+
+ // TODO(nlacasse): Test database.get/setPermissions.
+}
diff --git a/dart/test/syncbase_row_test.dart b/dart/test/syncbase_row_test.dart
new file mode 100644
index 0000000..1ce6643
--- /dev/null
+++ b/dart/test/syncbase_row_test.dart
@@ -0,0 +1,51 @@
+library syncbase_row_test;
+
+import 'dart:convert' show UTF8;
+
+import 'package:test/test.dart';
+
+import 'package:ether/syncbase_client.dart' show SyncbaseClient;
+
+import './utils.dart' as utils;
+
+runRowTests(SyncbaseClient c) {
+ test('getting a handle to a row', () {
+ var app = c.app(utils.uniqueName('app'));
+ var db = app.noSqlDatabase(utils.uniqueName('db'));
+ var table = db.table(utils.uniqueName('table'));
+
+ var rowName = utils.uniqueName('row');
+ var row = table.row(rowName);
+
+ expect(row.relativeName, equals(rowName));
+ expect(row.fullName, equals(table.fullName + '/' + rowName));
+ });
+
+ test('putting and getting a row', () 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());
+ var table = db.table(utils.uniqueName('table'));
+ await table.create(utils.emptyPerms());
+
+ var row = table.row(utils.uniqueName('row'));
+
+ expect(await row.exists(), equals(false));
+
+ var value1 = UTF8.encode("foo");
+ await row.put(value1);
+
+ expect(await row.exists(), equals(true));
+ expect(await row.get(), equals(value1));
+
+ var value2 = UTF8.encode("bar");
+ await row.put(value2);
+
+ expect(await row.exists(), equals(true));
+ expect(await row.get(), equals(value2));
+
+ await row.delete();
+ expect(await row.exists(), equals(false));
+ });
+}
diff --git a/dart/test/syncbase_table_test.dart b/dart/test/syncbase_table_test.dart
new file mode 100644
index 0000000..e0bfd46
--- /dev/null
+++ b/dart/test/syncbase_table_test.dart
@@ -0,0 +1,33 @@
+library syncbase_table_test;
+
+import 'package:test/test.dart';
+
+import 'package:ether/syncbase_client.dart' show SyncbaseClient;
+
+import './utils.dart' as utils;
+
+runTableTests(SyncbaseClient c) {
+ test('getting a handle to a table', () {
+ var app = c.app(utils.uniqueName('app'));
+ var db = app.noSqlDatabase(utils.uniqueName('db'));
+ var tableName = utils.uniqueName('table');
+ var table = db.table(tableName);
+ expect(table.relativeName, equals(tableName));
+ expect(table.fullName, equals(db.fullName + '/' + tableName));
+ });
+
+ test('creating and deleting a table', () 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());
+
+ var table = db.table(utils.uniqueName('table'));
+
+ expect(await table.exists(), equals(false));
+ await table.create(utils.emptyPerms());
+ expect(await table.exists(), equals(true));
+ await table.delete();
+ expect(await table.exists(), equals(false));
+ });
+}
diff --git a/dart/test/syncbase_test.dart b/dart/test/syncbase_test.dart
index 200c9d3..1a1f628 100755
--- a/dart/test/syncbase_test.dart
+++ b/dart/test/syncbase_test.dart
@@ -7,6 +7,12 @@
import 'package:ether/initialized_application.dart' show InitializedApplication;
import 'package:ether/syncbase_client.dart' show SyncbaseClient;
+// Import other test files.
+import './syncbase_app_test.dart' show runAppTests;
+import './syncbase_database_test.dart' show runDatabaseTests;
+import './syncbase_row_test.dart' show runRowTests;
+import './syncbase_table_test.dart' show runTableTests;
+
main(List args) async {
InitializedApplication app = new InitializedApplication.fromHandle(args[0]);
await app.initialized;
@@ -23,9 +29,11 @@
app.resetConnections();
});
- test('app(foo).exists() should be false', () {
- expect(c.app('foo').exists(), completion(isFalse));
- });
+ // Run imported tests.
+ runAppTests(c);
+ runDatabaseTests(c);
+ runTableTests(c);
+ runRowTests(c);
// Append a final test to terminate shell connection.
// TODO(nlacasse): Remove this once package 'test' supports a global tearDown
diff --git a/dart/test/utils.dart b/dart/test/utils.dart
new file mode 100644
index 0000000..37c4e8a
--- /dev/null
+++ b/dart/test/utils.dart
@@ -0,0 +1,18 @@
+library utils;
+
+import 'package:ether/syncbase_client.dart' show Perms;
+
+// Returns an empty Perms object.
+Perms emptyPerms() => new Perms()..json = '{}';
+
+// Returns the current timestamp in ms since epoch.
+int timestamp() => new DateTime.now().millisecondsSinceEpoch;
+
+int _nameCounter = timestamp();
+
+// Returns a new unique name.
+String uniqueName(String type) {
+ type ??= 'unknown';
+ _nameCounter++;
+ return type + '-' + _nameCounter.toString();
+}