Pass 'version' in syncgroup.setSpec.

The VDL method requires a version, but we didn't have one in the JS API.

Tests added.

Fixes vanadium/issues/648

Change-Id: Id1d45d290ec4d20fc41e1ffe23ad31eafcccdd2d
diff --git a/src/nosql/database.js b/src/nosql/database.js
index 4575ac1..58c0993 100644
--- a/src/nosql/database.js
+++ b/src/nosql/database.js
@@ -219,7 +219,7 @@
  * @param {module:vanadium.security.access.Permissions} perms Permissions for
  * the database.
  * @param {string} version Version of the current Permissions object which will
- * be over-written.  If empty, SetPermissions will perform an unconditional
+ * be overwritten. If empty, SetPermissions will perform an unconditional
  * update.
  * @param {function} cb Callback.
  */
diff --git a/src/nosql/syncgroup.js b/src/nosql/syncgroup.js
index 2fdce27..f7615b6 100644
--- a/src/nosql/syncgroup.js
+++ b/src/nosql/syncgroup.js
@@ -132,10 +132,12 @@
  *
  * @param {module:vanadium.context.Context} ctx Vanadium context.
  * @param {module:syncbase.nosql.SyncGroupSpec} spec SyncGroupSpec.
+ * @param {string} version Version of the current SyncGroupSpec object which
+ * will be overwritten. If empty, setSpec will perform an unconditional update.
  * @param {function} cb Callback.
  */
-SyncGroup.prototype.setSpec = function(ctx, spec, cb) {
-  this._db._wire(ctx).setSyncGroupSpec(ctx, this.name, spec, cb);
+SyncGroup.prototype.setSpec = function(ctx, spec, version, cb) {
+  this._db._wire(ctx).setSyncGroupSpec(ctx, this.name, spec, version, cb);
 };
 
 /**
diff --git a/test/integration/test-syncgroup.js b/test/integration/test-syncgroup.js
index 2ab187f..80a2666 100644
--- a/test/integration/test-syncgroup.js
+++ b/test/integration/test-syncgroup.js
@@ -253,3 +253,80 @@
     }
   });
 });
+
+test('syncgroup.get/setSpec', function(t) {
+  var perms = {};
+  var prefixes = ['biz/bazz'];
+
+  var firstVersion;
+
+  var newSpec = new nosql.SyncGroupSpec({
+    description: 'new spec'
+  });
+
+  var newSpec2 = new nosql.SyncGroupSpec({
+    description: 'another new spec'
+  });
+
+  setupSyncGroup(t, perms, prefixes, function(err, o) {
+    if (err) {
+      return t.end(err);
+    }
+
+    var sg = o.syncgroup;
+    var ctx = o.ctx;
+    sg.getSpec(ctx, assertSpec);
+
+    function assertSpec(err, spec, version) {
+      if (err) {
+        return done(err);
+      }
+
+      firstVersion = version;
+
+      t.deepEqual(spec.perms, perms, 'sg has correct perms');
+      t.deepEqual(spec.prefixes, prefixes, 'sg has correct prefixes');
+      t.equal(typeof version, 'string', 'version is string');
+
+      // Set spec with bogus version.
+      var bogusVersion = 'totally-bogus';
+
+      sg.setSpec(ctx, newSpec, bogusVersion, assertSetSpecFails);
+    }
+
+    function assertSetSpecFails(err) {
+      // TODO(nlacasse): Syncbase does not currently enforce that the version
+      // sent on SetSpec matches the current version.  Once it does enforce
+      // this, the following assertion should be uncommented.
+      // t.ok(err, 'setting spec with bogus version should fail');
+
+      // Set spec with empty version.
+      sg.setSpec(ctx, newSpec, '', assertSetSpecSucceeds);
+    }
+
+    function assertSetSpecSucceeds(err) {
+      if (err) {
+        return done(err);
+      }
+
+      sg.getSpec(ctx, assertGetSpec);
+    }
+
+    function assertGetSpec(err, spec, version) {
+      if (err) {
+        return done(err);
+      }
+
+      t.equal(spec.name, newSpec.name, 'spec has the correct name');
+      t.equal(typeof version, 'string', 'version is string');
+
+      // Set spec with previous version.
+      sg.setSpec(ctx, newSpec2, version, done);
+    }
+
+    function done(err) {
+      t.error(err);
+      o.teardown(t.end);
+    }
+  });
+});