Implement listApps, listDatabases, and listTables. Also start
refactoring the tests.
This CL depends on go/vcl/12071, otherwise the globbing is broken.
Change-Id: I7a1c48044a3fb77862f3f9c3df294a553f6973c1
diff --git a/src/app.js b/src/app.js
index 06b8b65..9452023 100644
--- a/src/app.js
+++ b/src/app.js
@@ -4,8 +4,8 @@
var vanadium = require('vanadium');
-var Database = require('./nosql/database').Database;
-var utils = require('./utils');
+var Database = require('./nosql/database');
+var util = require('./util');
var vdl = require('./gen-vdl/v.io/syncbase/v23/services/syncbase');
var wireSignature = vdl.App.prototype._serviceDescription;
@@ -17,7 +17,7 @@
return new App(parentFullName, relativeName);
}
- utils.addNameProperties(this, parentFullName, relativeName);
+ util.addNameProperties(this, parentFullName, relativeName);
/**
* Caches the database wire object.
@@ -37,7 +37,9 @@
};
// listDatabases returns of all database names.
-App.prototype.listDatabases = function(ctx) {};
+App.prototype.listDatabases = function(ctx, cb) {
+ util.getChildNames(ctx, this.fullName, cb);
+};
// create creates this app. If perms is empty, we inherit (copy) the Service
// perms.
diff --git a/src/nosql/batch-database.js b/src/nosql/batch-database.js
new file mode 100644
index 0000000..5f8c130
--- /dev/null
+++ b/src/nosql/batch-database.js
@@ -0,0 +1,59 @@
+// 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.
+
+module.exports = BatchDatabase;
+
+/*
+ * A handle to a set of reads and writes to the database that should be
+ * considered an atomic unit. See beginBatch() for concurrency semantics.
+ * @constructor
+ * @param {module:vanadium.syncbase.database.Database} db Database.
+ */
+function BatchDatabase(db) {
+ if (!(this instanceof BatchDatabase)) {
+ return new BatchDatabase(db);
+ }
+
+ this._db = db;
+
+ throw new Error('not implemented');
+}
+
+/**
+ * Returns the Table with the given name.
+ * @param {string} relativeName Table name. Must not contain slashes.
+ * @return {module:syncbase.table.Table} Table object.
+ */
+BatchDatabase.prototype.table = function(ctx, relativeName, cb) {
+ return this._db.table(ctx, relativeName, cb);
+};
+
+/**
+ * Returns a list of all Table names.
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {function} cb Callback.
+ */
+BatchDatabase.prototype.listTables = function(ctx, cb) {
+ return this._db.listTables(ctx, cb);
+};
+
+/**
+ * Persists the pending changes to the database.
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {function} cb Callback.
+ */
+BatchDatabase.prototype.commit = function(ctx, cb) {
+ cb(new Error('not implemented'));
+};
+
+/**
+ * Notifies the server that any pending changes can be discarded. It is not
+ * strictly required, but it may allow the server to release locks or other
+ * resources sooner than if it was not called.
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {function} cb Callback.
+ */
+BatchDatabase.prototype.abort = function(ctx, cb) {
+ cb(new Error('not implemented'));
+};
diff --git a/src/nosql/database.js b/src/nosql/database.js
index ba51d48..deaee2b 100644
--- a/src/nosql/database.js
+++ b/src/nosql/database.js
@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+module.exports = Database;
+
var vanadium = require('vanadium');
var nosqlVdl = require('../gen-vdl/v.io/syncbase/v23/services/syncbase/nosql');
var Table = require('./table');
-var utils = require('../utils');
+var util = require('../util');
/**
* Database represents a collection of Tables. Batches, queries, sync, watch,
@@ -22,7 +24,7 @@
return new Database(parentFullName, relativeName);
}
- utils.addNameProperties(this, parentFullName, relativeName);
+ util.addNameProperties(this, parentFullName, relativeName);
/**
* Caches the database wire object.
@@ -84,7 +86,7 @@
* @param {function} cb Callback.
*/
Database.prototype.listTables = function(ctx, cb) {
- return cb(new Error('not implemented'));
+ util.getChildNames(ctx, this.fullName, cb);
};
/**
@@ -162,7 +164,7 @@
* Configuration options for Batches.
* @constructor
*/
-var BatchOptions = nosqlVdl.BatchOptions;
+Database.BatchOptions = nosqlVdl.BatchOptions;
/**
* Creates a new batch. Instead of calling this function directly, clients are
@@ -181,69 +183,9 @@
*
* Concurrency semantics can be configured using BatchOptions.
* @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {module:vanadium.syncbase.database.BatchOptions} opts BatchOptions.
+ * @param {module:vanadium.syncbase.Database.BatchOptions} opts BatchOptions.
* @param {function} cb Callback.
*/
Database.prototype.beginBatch = function(ctx, opts, cb) {
cb(new Error('not implemented'));
};
-
-/*
- * A handle to a set of reads and writes to the database that should be
- * considered an atomic unit. See beginBatch() for concurrency semantics.
- * @constructor
- * @param {module:vanadium.syncbase.database.Database} db Database.
- */
-function BatchDatabase(db) {
- if (!(this instanceof BatchDatabase)) {
- return new BatchDatabase(db);
- }
-
- this._db = db;
-
- throw new Error('not implemented');
-}
-
-/**
- * Returns the Table with the given name.
- * @param {string} relativeName Table name. Must not contain slashes.
- * @return {module:syncbase.table.Table} Table object.
- */
-BatchDatabase.prototype.table = function(ctx, relativeName, cb) {
- return this._db.table(ctx, relativeName, cb);
-};
-
-/**
- * Returns a list of all Table names.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-BatchDatabase.prototype.listTables = function(ctx, cb) {
- return this._db.listTables(ctx, cb);
-};
-
-/**
- * Persists the pending changes to the database.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-BatchDatabase.prototype.commit = function(ctx, cb) {
- cb(new Error('not implemented'));
-};
-
-/**
- * Notifies the server that any pending changes can be discarded. It is not
- * strictly required, but it may allow the server to release locks or other
- * resources sooner than if it was not called.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-BatchDatabase.prototype.abort = function(ctx, cb) {
- cb(new Error('not implemented'));
-};
-
-module.exports = {
- BatchDatabase: BatchDatabase,
- BatchOptions: BatchOptions,
- Database: Database
-};
diff --git a/src/nosql/index.js b/src/nosql/index.js
deleted file mode 100644
index 149478f..0000000
--- a/src/nosql/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-var Database = require('./database');
-var runInBatch = require('./batch');
-
-module.exports = {
- newDatabase: newDatabase,
- runInBatch: runInBatch
-};
-
-function newDatabase(name, relativeName) {
- return new Database(name, relativeName);
-}
\ No newline at end of file
diff --git a/src/nosql/table.js b/src/nosql/table.js
index 47dc45d..cca247a 100644
--- a/src/nosql/table.js
+++ b/src/nosql/table.js
@@ -4,7 +4,7 @@
module.exports = Table;
-var utils = require('../utils');
+var util = require('../util');
// Table represents a collection of Rows.
function Table(parentFullName, relativeName) {
@@ -12,7 +12,7 @@
return new Table(parentFullName, relativeName);
}
- utils.addNameProperties(this, parentFullName, relativeName);
+ util.addNameProperties(this, parentFullName, relativeName);
}
// Row returns the Row with the given primary key.
diff --git a/src/service.js b/src/service.js
index 8874165..a8c61c1 100644
--- a/src/service.js
+++ b/src/service.js
@@ -5,6 +5,7 @@
var vanadium = require('vanadium');
var App = require('./app');
+var util = require('./util');
var vdl = require('./gen-vdl/v.io/syncbase/v23/services/syncbase');
// TODO(aghassemi): This looks clunky,
@@ -47,25 +48,7 @@
// listApps returns a list of all app names.
Service.prototype.listApps = function(ctx, cb) {
- var rt = vanadium.runtimeForContext(ctx);
- var namespace = rt.namespace();
- var appNames = [];
-
- //TODO(nlacasse): Refactor the glob->list into a common util
- var stream = namespace.glob(ctx, vanadium.naming.join(this.fullName, '*'),
- function(err) {
- if (err) {
- return cb(err);
- }
-
- cb(null, appNames);
- }).stream;
-
- stream.on('data', function(globResult) {
- var fullName = globResult.name;
- var name = vanadium.naming.basename(fullName);
- appNames.push(name);
- });
+ util.getChildNames(ctx, this.fullName, cb);
};
Service.prototype.getPermissions = function(ctx, cb) {
diff --git a/src/utils.js b/src/util.js
similarity index 60%
rename from src/utils.js
rename to src/util.js
index bee3858..3e1775c 100644
--- a/src/utils.js
+++ b/src/util.js
@@ -7,6 +7,7 @@
module.exports = {
addNameProperties: addNameProperties,
+ getChildNames: getChildNames,
InvalidNameError: InvalidNameError
};
@@ -49,3 +50,32 @@
}
inherits(InvalidNameError, Error);
+/**
+ * getChildNames returns all names that are children of the parentFullName.
+ * @private
+ */
+function getChildNames(ctx, parentFullName, cb) {
+ var rt = vanadium.runtimeForContext(ctx);
+ var namespace = rt.namespace();
+ var childNames = [];
+
+ var globPattern = vanadium.naming.join(parentFullName, '*');
+
+ var stream = namespace.glob(ctx, globPattern, function(err) {
+ if (err) {
+ return cb(err);
+ }
+
+ cb(null, childNames);
+ }).stream;
+
+ stream.on('data', function(globResult) {
+ var fullName = globResult.name;
+ var name = vanadium.naming.basename(fullName);
+ childNames.push(name);
+ });
+
+ stream.on('error', function(err) {
+ console.error('Stream error: ' + JSON.stringify(err));
+ });
+}
diff --git a/test/integration/test-app.js b/test/integration/test-app.js
index 3423de4..73838c2 100644
--- a/test/integration/test-app.js
+++ b/test/integration/test-app.js
@@ -8,30 +8,11 @@
var syncbase = require('../..');
-var testUtils = require('./utils');
-var setup = testUtils.setupService;
-var uniqueName = testUtils.uniqueName;
-
-var DEFAULT_PERMISSIONS = new Map([
- ['Read', {
- 'in': ['...'],
- 'notIn': []
- }],
- ['Write', {
- 'in': ['...'],
- 'notIn': []
- }],
- ['Admin', {
- 'in': ['...'],
- 'notIn': []
- }]
-]);
-
-/*
- * TODO(aghassemi) We should refactor some of the testing functionality,
- * specially around verifying children and setting/getting permissions, into a
- * common util as these types of test will be common across different layers.
- */
+var testUtil = require('./util');
+var appExists = testUtil.appExists;
+var setupApp = testUtil.setupApp;
+var setupService = testUtil.setupService;
+var uniqueName = testUtil.uniqueName;
test('Creating a service and checking its full name', function(t) {
var mockServiceName = 'foo/bar/baz';
@@ -42,7 +23,7 @@
});
test('Getting a handle to an app', function(t) {
- setup(t, function(err, o) {
+ setupService(t, function(err, o) {
if (err) {
return t.end(err, 'Failed to setup');
}
@@ -60,195 +41,67 @@
});
test('Creating and listing apps', function(t) {
- setup(t, function(err, o) {
+ setupService(t, function(err, o) {
if (err) {
return t.end(err, 'Failed to setup');
}
- // Create multiple apps
- var expectedAppNames = [
+ // Create multiple apps.
+ var appNames = [
uniqueName('app'),
uniqueName('app'),
uniqueName('app')
];
-
- createAppsAndVerifyExistance(t, o.service, o.ctx, expectedAppNames,
- function() {
- o.teardown(t.end);
+ async.forEach(appNames, function(appName, cb) {
+ o.service.app(appName).create(o.ctx, {}, cb);
+ }, function(err) {
+ if (err) {
+ t.error(err);
+ return o.teardown(t.end);
}
- );
+
+ // Verify each app exists.
+ async.map(appNames, function(appName, cb) {
+ appExists(o.ctx, o.service, appName, cb);
+ }, function(err, existsArray) {
+ t.error(err);
+ t.deepEqual(existsArray, [true, true, true], 'all apps exist');
+ o.teardown(t.end);
+ });
+ });
});
});
test('Deleting an app', function(t) {
- setup(t, function(err, o) {
+ setupApp(t, function(err, o) {
if (err) {
return t.end(err);
}
- var appName = uniqueName('app');
-
- createAppsAndVerifyExistance(t, o.service, o.ctx, [appName], deleteApp);
-
- function deleteApp() {
- o.service.app(appName).delete(o.ctx, verifyItNoLongerExists);
- }
-
- function verifyItNoLongerExists(err) {
+ o.app.delete(o.ctx, function(err) {
if (err) {
- t.fail(err, 'Failed to delete app');
+ t.error(err);
return o.teardown(t.end);
}
- o.service.listApps(o.ctx, function(err, apps) {
- if (err) {
- t.fail(err, 'Failed to list apps');
- return o.teardown(t.end);
- }
-
- t.ok(apps.indexOf(appName) < 0, 'App is no longer listed');
- return o.teardown(t.end);
+ appExists(o.ctx, o.service, o.app.name, function(err, exists) {
+ t.error(err);
+ t.notok(exists, 'app no longer exists');
+ o.teardown(t.end);
});
- }
- });
-});
-
-test('Getting permissions of an app', function(t) {
- setup(t, function(err, o) {
- if (err) {
- return t.end(err);
- }
-
- var appName = uniqueName('app');
-
- createAppsAndVerifyExistance(t, o.service, o.ctx, [appName],
- getPermissions);
-
- function getPermissions() {
- o.service.app(appName).getPermissions(o.ctx, verifyPermissions);
- }
-
- function verifyPermissions(err, perms, version) {
- if (err) {
- t.fail(err, 'Failed to get permissions for app');
- return o.teardown(t.end);
- }
-
- t.equal(perms.size, DEFAULT_PERMISSIONS.size,
- 'Permissions size matches');
- DEFAULT_PERMISSIONS.forEach(function(value, key) {
- t.deepEqual(perms.get(key), value, 'Permission value matches');
- });
- t.equal(version, '0', 'Version matches');
-
- return o.teardown(t.end);
- }
- });
-});
-
-test('Setting permissions of an app', function(t) {
- setup(t, function(err, o) {
- if (err) {
- return t.end(err);
- }
-
- var appName = uniqueName('app');
- var NEW_PERMS = new Map([
- ['Read', {
- 'in': ['...', 'canRead'],
- 'notIn': ['cantRead']
- }],
- ['Write', {
- 'in': ['...', 'canWrite'],
- 'notIn': ['cantWrite']
- }],
- ['Admin', {
- 'in': ['...', 'canAdmin'],
- 'notIn': ['cantAdmin']
- }]
- ]);
-
- createAppsAndVerifyExistance(t, o.service, o.ctx, [appName],
- setPermissions);
-
- function setPermissions() {
- o.service.app(appName)
- .setPermissions(o.ctx, NEW_PERMS, '0', getPermissions);
- }
-
- function getPermissions(err) {
- if (err) {
- t.fail(err, 'Failed to set permissions for app');
- return o.teardown(t.end);
- }
- o.service.app(appName).getPermissions(o.ctx, verifyPermissions);
- }
-
- function verifyPermissions(err, perms, version) {
- if (err) {
- t.fail(err, 'Failed to get permissions for app');
- return o.teardown(t.end);
- }
-
- t.equal(perms.size, NEW_PERMS.size,
- 'Permissions size matches');
- NEW_PERMS.forEach(function(value, key) {
- t.deepEqual(perms.get(key), value, 'Permission value matches');
- });
- // Version should have been incremented after setPermission call
- t.equal(version, '1', 'Version matches');
-
- return o.teardown(t.end);
- }
- });
-});
-
-// Helper function that creates bunch apps in parallel and calls the callback
-// when all are created.
-function createAppsAndVerifyExistance(t, service, ctx, appNames, cb) {
- async.parallel(create(), verify);
-
- // Returns an array of functions that create apps for the given appNames.
- function create() {
- return appNames.map(function(appName) {
- return function(callback) {
- service.app(appName).create(ctx, DEFAULT_PERMISSIONS, callback);
- };
});
- }
+ });
+});
- function verify(err) {
+test('Getting/Setting permissions of an app', function(t) {
+ setupApp(t, function(err, o) {
if (err) {
- t.fail('Failed to create apps');
- return cb(err);
+ return t.end(err);
}
- service.listApps(ctx, verifyResults);
-
- function verifyResults(err, apps) {
- if (err) {
- t.fail(err, 'Failed to list apps');
- return cb(err);
- }
-
- var matchCounter = 0;
- appNames.forEach(function(appName) {
- if (apps.indexOf(appName) >= 0) {
- matchCounter++;
- }
- });
-
- var diff = appNames.length - matchCounter;
- if (diff === 0) {
- t.pass('All ' + matchCounter + ' expected app name(s) were listed');
- return cb();
- } else {
- var failedErr = new Error(
- 'Some (' + diff + ') expected app name(s) were not listed'
- );
- t.fail(failedErr);
- return cb(failedErr);
- }
- }
- }
-}
+ testUtil.testGetSetPermissions(t, o.ctx, o.app, function(err) {
+ t.error(err);
+ return o.teardown(t.end);
+ });
+ });
+});
diff --git a/test/integration/test-database.js b/test/integration/test-database.js
index acf06ac..d24ab17 100644
--- a/test/integration/test-database.js
+++ b/test/integration/test-database.js
@@ -6,13 +6,15 @@
var test = require('prova');
var vanadium = require('vanadium');
-var Database = require('../../src/nosql/database').Database;
+var Database = require('../../src/nosql/database');
var Table = require('../../src/nosql/table');
-var testUtils = require('./utils');
-var uniqueName = testUtils.uniqueName;
-var setupApp = testUtils.setupApp;
-var setupDatabase = testUtils.setupDatabase;
+var testUtil = require('./util');
+var databaseExists = testUtil.databaseExists;
+var tableExists = testUtil.tableExists;
+var setupApp = testUtil.setupApp;
+var setupDatabase = testUtil.setupDatabase;
+var uniqueName = testUtil.uniqueName;
test('app.noSqlDatabase() returns a database', function(t) {
setupApp(t, function(err, o) {
@@ -64,12 +66,16 @@
var db = o.app.noSqlDatabase(uniqueName('db'));
db.create(o.ctx, {}, function(err) {
- t.error(err);
+ if (err) {
+ t.error(err);
+ return o.teardown(t.end);
+ }
- // TODO(nlacasse): Verify that the database exists using
- // app.listDatabases(), once that function has been implemented.
-
- o.teardown(t.end);
+ databaseExists(o.ctx, o.app, db.name, function(err, exists) {
+ t.error(err);
+ t.ok(exists, 'database exists');
+ o.teardown(t.end);
+ });
});
});
});
@@ -113,12 +119,16 @@
}
db.delete(o.ctx, function(err) {
- t.error(err);
+ if (err) {
+ t.error(err);
+ return o.teardown(t.end);
+ }
- // TODO(nlacasse): Verify that the database no longer exists using
- // app.listDatabases(), once that function has been implemented.
-
- o.teardown(t.end);
+ databaseExists(o.ctx, o.app, db.name, function(err, exists) {
+ t.error(err);
+ t.notok(exists, 'database does not exist');
+ o.teardown(t.end);
+ });
});
});
});
@@ -169,12 +179,16 @@
var tableName = uniqueName('table');
db.createTable(o.ctx, tableName, {}, function(err) {
- t.error(err);
+ if (err) {
+ t.error(err);
+ return o.teardown(t.end);
+ }
- // TODO(nlacasse): Verify that the table exists using db.listTables(),
- // once that function has been implemented.
-
- o.teardown(t.end);
+ tableExists(o.ctx, db, tableName, function(err, exists) {
+ t.error(err);
+ t.ok(exists, 'table exists');
+ o.teardown(t.end);
+ });
});
});
});
@@ -195,12 +209,16 @@
}
db.deleteTable(o.ctx, tableName, function(err) {
- t.error(err);
+ if (err) {
+ t.error(err);
+ return o.teardown(t.end);
+ }
- // TODO(nlacasse): Verify that the table no longer exists using
- // db.listTables(), once that function has been implemented.
-
- o.teardown(t.end);
+ tableExists(o.ctx, db, tableName, function(err, exists) {
+ t.error(err);
+ t.notok(exists, 'table does not exist');
+ o.teardown(t.end);
+ });
});
});
});
@@ -221,3 +239,16 @@
});
});
});
+
+test('Getting/Setting permissions of a database', function(t) {
+ setupDatabase(t, function(err, o) {
+ if (err) {
+ return t.end(err);
+ }
+
+ testUtil.testGetSetPermissions(t, o.ctx, o.database, function(err) {
+ t.error(err);
+ return o.teardown(t.end);
+ });
+ });
+});
diff --git a/test/integration/util.js b/test/integration/util.js
new file mode 100644
index 0000000..c5730e8
--- /dev/null
+++ b/test/integration/util.js
@@ -0,0 +1,185 @@
+// 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.
+
+module.exports = {
+ appExists: appExists,
+ databaseExists: databaseExists,
+ tableExists: tableExists,
+
+ setupApp: setupApp,
+ setupDatabase: setupDatabase,
+ setupService: setupService,
+
+ uniqueName: uniqueName,
+
+ testGetSetPermissions: testGetSetPermissions
+};
+
+var vanadium = require('vanadium');
+var extend = require('xtend');
+
+var syncbase = require('../..');
+
+var SERVICE_NAME = require('./service-name');
+
+// Helper function to generate unique names.
+var nameCounter = 0;
+function uniqueName(prefix) {
+ prefix = prefix || 'name';
+ return prefix + '_' + nameCounter++;
+}
+
+// Initializes Vanadium runtime.
+function setupService(t, cb) {
+ vanadium.init(function(err, rt) {
+ if (err) {
+ return cb(err);
+ }
+
+ function teardown(cb) {
+ rt.close(function(err) {
+ t.error(err, 'rt.close should not error.');
+ cb(null);
+ });
+ }
+
+ var service = syncbase.newService(SERVICE_NAME);
+
+ return cb(null, {
+ ctx: rt.getContext(),
+ rt: rt,
+ service: service,
+ teardown: teardown
+ });
+ });
+}
+
+// Initializes Vanadium runtime and creates an App.
+function setupApp(t, cb) {
+ setupService(t, function(err, o) {
+ if (err) {
+ return cb(err);
+ }
+
+ var app = o.service.app(uniqueName('app'));
+
+ app.create(o.ctx, {}, function(err) {
+ if (err) {
+ o.rt.close(t.error);
+ return cb(err);
+ }
+
+ return cb(null, extend(o, {
+ app:app
+ }));
+ });
+ });
+}
+
+// Initializes Vanadium runtime and creates an App and a Database.
+function setupDatabase(t, cb) {
+ setupApp(t, function(err, o) {
+
+ var db = o.app.noSqlDatabase(uniqueName('db'));
+
+ db.create(o.ctx, {}, function(err) {
+ if (err) {
+ o.rt.close(t.error);
+ return cb(err);
+ }
+
+ return cb(null, extend(o, {
+ database: db
+ }));
+ });
+ });
+}
+
+// Assert that two permissions objects are equal.
+function assertPermissionsEqual(t, got, want) {
+ t.equal(got.size, want.size, 'Permissions size matches');
+ want.forEach(function(value, key) {
+ t.deepEqual(got.get(key), value, 'Permission value matches');
+ });
+}
+
+// For any object that implements get/setPermissions, test that getting and
+// setting permissions behaves as it should.
+function testGetSetPermissions(t, ctx, obj, cb){
+ obj.getPermissions(ctx, function(err, perms, version) {
+ if (err) {
+ t.error('error getting permissions ' + err);
+ return cb(err);
+ }
+
+ t.ok(perms, 'Has permissions');
+ t.ok(version, 'Has a version');
+
+ var newPerms = new Map([
+ ['Read', {
+ 'in': ['...', 'canRead'],
+ 'notIn': ['cantRead']
+ }],
+ ['Write', {
+ 'in': ['...', 'canWrite'],
+ 'notIn': ['cantWrite']
+ }],
+ ['Admin', {
+ 'in': ['...', 'canAdmin'],
+ 'notIn': ['cantAdmin']
+ }]
+ ]);
+
+ obj.setPermissions(ctx, newPerms, version, function(err) {
+ if (err) {
+ t.error('error setting permissions ' + err);
+ return cb(err);
+ }
+
+ obj.getPermissions(ctx, function(err, gotPerms, gotVersion) {
+ if (err) {
+ t.error('error getting permissions ' + err);
+ return cb(err);
+ }
+
+ t.ok(perms, 'Has permissions');
+ t.ok(version, 'Has a version');
+
+ t.notEqual(version, gotVersion, 'should have a new version');
+ assertPermissionsEqual(t, gotPerms, newPerms);
+ return cb(null);
+ });
+ });
+ });
+}
+
+function appExists(ctx, service, name, cb) {
+ service.listApps(ctx, function(err, names) {
+ if (err) {
+ return cb(err);
+ }
+
+ cb(null, names.indexOf(name) >= 0);
+ });
+}
+
+function databaseExists(ctx, app, name, cb) {
+ app.listDatabases(ctx, function(err, names) {
+ if (err) {
+ return cb(err);
+ }
+
+ cb(null, names.indexOf(name) >= 0);
+ });
+}
+
+function tableExists(ctx, db, name, cb) {
+ db.listTables(ctx, function(err, names) {
+ if (err) {
+ return cb(err);
+ }
+
+ cb(null, names.indexOf(name) >= 0);
+ });
+}
diff --git a/test/integration/utils.js b/test/integration/utils.js
deleted file mode 100644
index 89cf8c5..0000000
--- a/test/integration/utils.js
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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.
-
-var vanadium = require('vanadium');
-var extend = require('xtend');
-
-var syncbase = require('../..');
-
-var SERVICE_NAME = require('./service-name');
-
-// Helper function to generate unique names.
-var uniqueName = (function() {
- var i = 0;
- return function(prefix) {
- prefix = prefix || 'name';
- i++;
- return prefix + '_' + i;
- };
-})();
-
-// Initializes Vanadium runtime.
-function setupService(t, cb) {
- vanadium.init(function(err, rt) {
- if (err) {
- return cb(err);
- }
-
- function teardown(cb) {
- rt.close(function(err) {
- t.error(err, 'rt.close should not error.');
- cb(null);
- });
- }
-
- var service = syncbase.newService(SERVICE_NAME);
-
- return cb(null, {
- ctx: rt.getContext(),
- rt: rt,
- service: service,
- teardown: teardown
- });
- });
-}
-
-// Initializes Vanadium runtime and creates an App.
-function setupApp(t, cb) {
- setupService(t, function(err, o) {
- if (err) {
- return cb(err);
- }
-
- var app = o.service.app(uniqueName('app'));
-
- app.create(o.ctx, {}, function(err) {
- if (err) {
- o.rt.close(t.error);
- return cb(err);
- }
-
- return cb(null, extend(o, {
- app:app
- }));
- });
- });
-}
-
-// Initializes Vanadium runtime and creates an App and a Database.
-function setupDatabase(t, cb) {
- setupApp(t, function(err, o) {
-
- var db = o.app.noSqlDatabase(uniqueName('db'));
-
- db.create(o.ctx, {}, function(err) {
- if (err) {
- o.rt.close(t.error);
- return cb(err);
- }
-
- return cb(null, extend(o, {
- database: db
- }));
- });
- });
-}
-
-module.exports = {
- setupApp: setupApp,
- setupDatabase: setupDatabase,
- setupService: setupService,
- uniqueName: uniqueName
-};