couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject [1/2] split replicator_db tests
Date Sun, 13 Jan 2013 15:09:22 GMT
http://git-wip-us.apache.org/repos/asf/couchdb/blob/92795eb2/share/www/script/test/replicator_db_simple.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/replicator_db_simple.js b/share/www/script/test/replicator_db_simple.js
new file mode 100644
index 0000000..f7acedb
--- /dev/null
+++ b/share/www/script/test/replicator_db_simple.js
@@ -0,0 +1,114 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.replicator_db_simple = function(debug) {
+
+  if (debug) debugger;
+
+  var populate_db = replicator_db.populate_db;
+  var docs1 = replicator_db.docs1;
+  var dbA = replicator_db.dbA;
+  var dbB = replicator_db.dbB;
+  var repDb = replicator_db.repDb;
+  var waitForRep = replicator_db.waitForRep;
+
+  function simple_replication() {
+    populate_db(dbA, docs1);
+    populate_db(dbB, []);
+
+    var repDoc = {
+      _id: "foo_simple_rep",
+      source: dbA.name,
+      target: dbB.name
+    };
+    T(repDb.save(repDoc).ok);
+
+    waitForRep(repDb, repDoc, "completed");
+    for (var i = 0; i < docs1.length; i++) {
+      var doc = docs1[i];
+      var copy = dbB.open(doc._id);
+      T(copy !== null);
+      T(copy.value === doc.value);
+    }
+
+    var repDoc1 = repDb.open(repDoc._id);
+    T(repDoc1 !== null);
+    T(repDoc1.source === repDoc.source);
+    T(repDoc1.target === repDoc.target);
+    T(repDoc1._replication_state === "completed", "simple");
+    T(typeof repDoc1._replication_state_time === "string");
+    T(typeof repDoc1._replication_id  === "string");
+    T(typeof repDoc1._replication_stats === "object", "doc has stats");
+    var stats = repDoc1._replication_stats;
+    TEquals(docs1.length, stats.revisions_checked,
+       "right # of revisions_checked");
+    TEquals(docs1.length, stats.missing_revisions_found,
+      "right # of missing_revisions_found");
+    TEquals(docs1.length, stats.docs_read, "right # of docs_read");
+    TEquals(docs1.length, stats.docs_written, "right # of docs_written");
+    TEquals(0, stats.doc_write_failures, "right # of doc_write_failures");
+    TEquals(dbA.info().update_seq, stats.checkpointed_source_seq,
+      "right checkpointed_source_seq");
+  }
+
+  var server_config = [
+    {
+      section: "couch_httpd_auth",
+      key: "iterations",
+      value: "1"
+    },
+    {
+      section: "replicator",
+      key: "db",
+      value: repDb.name
+    }
+  ];
+
+  repDb.deleteDb();
+  run_on_modified_server(server_config, simple_replication);
+
+/*
+ * Disabled, since error state would be set on the document only after
+ * the exponential backoff retry done by the replicator database listener
+ * terminates, which takes too much time for a unit test.
+ */
+ /*
+   function error_state_replication() {
+    populate_db(dbA, docs1);
+
+    var repDoc = {
+      _id: "foo_error_rep",
+      source: dbA.name,
+      target: "nonexistent_test_db"
+    };
+    T(repDb.save(repDoc).ok);
+
+    waitForRep(repDb, repDoc, "error");
+    var repDoc1 = repDb.open(repDoc._id);
+    T(repDoc1 !== null);
+    T(repDoc1._replication_state === "error");
+    T(typeof repDoc1._replication_state_time === "string");
+    T(typeof repDoc1._replication_id  === "string");
+  }
+ */
+/*
+ * repDb.deleteDb();
+ * restartServer();
+ * run_on_modified_server(server_config, error_state_replication);
+ */
+
+
+  // cleanup
+  repDb.deleteDb();
+  dbA.deleteDb();
+  dbB.deleteDb();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb/blob/92795eb2/share/www/script/test/replicator_db_successive.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/replicator_db_successive.js b/share/www/script/test/replicator_db_successive.js
new file mode 100644
index 0000000..4898c33
--- /dev/null
+++ b/share/www/script/test/replicator_db_successive.js
@@ -0,0 +1,127 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.replicator_db_successive = function(debug) {
+
+  if (debug) debugger;
+
+  var populate_db = replicator_db.populate_db;
+  var docs1 = replicator_db.docs1;
+  var dbA = replicator_db.dbA;
+  var dbB = replicator_db.dbB;
+  var repDb = replicator_db.repDb;
+  var wait = replicator_db.wait;
+  var waitForRep = replicator_db.waitForRep;
+  var waitForSeq = replicator_db.waitForSeq;
+
+  function successive_identical_replications() {
+    populate_db(dbA, docs1);
+    populate_db(dbB, []);
+
+    var repDoc1 = {
+      _id: "foo_ident_rep_1",
+      source: dbA.name,
+      target: dbB.name
+    };
+    T(repDb.save(repDoc1).ok);
+
+    waitForRep(repDb, repDoc1, "completed");
+    for (var i = 0; i < docs1.length; i++) {
+      var doc = docs1[i];
+      var copy = dbB.open(doc._id);
+      T(copy !== null);
+      T(copy.value === doc.value);
+    }
+
+    var repDoc1_copy = repDb.open(repDoc1._id);
+    T(repDoc1_copy !== null);
+    T(repDoc1_copy.source === repDoc1.source);
+    T(repDoc1_copy.target === repDoc1.target);
+    T(repDoc1_copy._replication_state === "completed");
+    T(typeof repDoc1_copy._replication_state_time === "string");
+    T(typeof repDoc1_copy._replication_id  === "string");
+    T(typeof repDoc1_copy._replication_stats === "object", "doc has stats");
+    var stats = repDoc1_copy._replication_stats;
+    TEquals(docs1.length, stats.revisions_checked,
+      "right # of revisions_checked");
+    TEquals(docs1.length, stats.missing_revisions_found,
+      "right # of missing_revisions_found");
+    TEquals(docs1.length, stats.docs_read, "right # of docs_read");
+    TEquals(docs1.length, stats.docs_written, "right # of docs_written");
+    TEquals(0, stats.doc_write_failures, "right # of doc_write_failures");
+    TEquals(dbA.info().update_seq, stats.checkpointed_source_seq,
+      "right checkpointed_source_seq");
+
+    var newDoc = {
+      _id: "doc666",
+      value: 666
+    };
+    T(dbA.save(newDoc).ok);
+
+    wait(200);
+    var newDoc_copy = dbB.open(newDoc._id);
+    // not replicated because first replication is complete (not continuous)
+    T(newDoc_copy === null);
+
+    var repDoc2 = {
+      _id: "foo_ident_rep_2",
+      source: dbA.name,
+      target: dbB.name
+    };
+    T(repDb.save(repDoc2).ok);
+
+    waitForRep(repDb, repDoc2, "completed");
+    var newDoc_copy = dbB.open(newDoc._id);
+    T(newDoc_copy !== null);
+    T(newDoc_copy.value === newDoc.value);
+
+    var repDoc2_copy = repDb.open(repDoc2._id);
+    T(repDoc2_copy !== null);
+    T(repDoc2_copy.source === repDoc1.source);
+    T(repDoc2_copy.target === repDoc1.target);
+    T(repDoc2_copy._replication_state === "completed");
+    T(typeof repDoc2_copy._replication_state_time === "string");
+    T(typeof repDoc2_copy._replication_id === "string");
+    T(repDoc2_copy._replication_id === repDoc1_copy._replication_id);
+    T(typeof repDoc2_copy._replication_stats === "object", "doc has stats");
+    stats = repDoc2_copy._replication_stats;
+    TEquals(1, stats.revisions_checked, "right # of revisions_checked");
+    TEquals(1, stats.missing_revisions_found,
+      "right # of missing_revisions_found");
+    TEquals(1, stats.docs_read, "right # of docs_read");
+    TEquals(1, stats.docs_written, "right # of docs_written");
+    TEquals(0, stats.doc_write_failures, "right # of doc_write_failures");
+    TEquals(dbA.info().update_seq, stats.checkpointed_source_seq,
+      "right checkpointed_source_seq");
+  }
+
+  var server_config = [
+    {
+      section: "couch_httpd_auth",
+      key: "iterations",
+      value: "1"
+    },
+    {
+      section: "replicator",
+      key: "db",
+      value: repDb.name
+    }
+  ];
+
+  repDb.deleteDb();
+  run_on_modified_server(server_config, successive_identical_replications);
+
+  // cleanup
+  repDb.deleteDb();
+  dbA.deleteDb();
+  dbB.deleteDb();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb/blob/92795eb2/share/www/script/test/replicator_db_survives.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/replicator_db_survives.js b/share/www/script/test/replicator_db_survives.js
new file mode 100644
index 0000000..dcaa101
--- /dev/null
+++ b/share/www/script/test/replicator_db_survives.js
@@ -0,0 +1,128 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.replicator_db_survives = function(debug) {
+
+  if (debug) debugger;
+
+  var populate_db = replicator_db.populate_db;
+  var docs1 = replicator_db.docs1;
+  var dbA = replicator_db.dbA;
+  var dbB = replicator_db.dbB;
+  var repDb = replicator_db.repDb;
+  var usersDb = replicator_db.usersDb;
+  var wait = replicator_db.wait;
+  var waitForRep = replicator_db.waitForRep;
+  var waitForSeq = replicator_db.waitForSeq;
+  var waitForDocPos = replicator_db.waitForDocPos;
+  var wait_rep_doc = replicator_db.wait_rep_doc;
+
+  function continuous_replication_survives_restart() {
+    var origRepDbName = CouchDB.request(
+      "GET", "/_config/replicator/db").responseText;
+
+    repDb.deleteDb();
+
+    var xhr = CouchDB.request("PUT", "/_config/replicator/db", {
+      body : JSON.stringify(repDb.name),
+      headers: {"X-Couch-Persist": "false"}
+    });
+    T(xhr.status === 200);
+
+    repDb.createDb(); // the config put above should create this db
+
+    populate_db(dbA, docs1);
+    populate_db(dbB, []);
+
+    var repDoc = {
+      _id: "foo_cont_rep_survives_doc",
+      source: dbA.name,
+      target: dbB.name,
+      continuous: true
+    };
+
+    T(repDb.save(repDoc).ok);
+
+    waitForSeq(dbA, dbB);
+    for (var i = 0; i < docs1.length; i++) {
+      var doc = docs1[i];
+      var copy = dbB.open(doc._id);
+      T(copy !== null);
+      T(copy.value === doc.value);
+    }
+
+    repDb.ensureFullCommit();
+    dbA.ensureFullCommit();
+
+    restartServer();
+
+    xhr = CouchDB.request("PUT", "/_config/replicator/db", {
+      body : JSON.stringify(repDb.name),
+      headers: {"X-Couch-Persist": "false"}
+    });
+
+    T(xhr.status === 200);
+
+    // add another doc to source, it will be replicated to target
+    var docX = {
+      _id: "foo1000",
+      value: 1001
+    };
+
+    T(dbA.save(docX).ok);
+
+    waitForSeq(dbA, dbB);
+    var copy = dbB.open("foo1000");
+    T(copy !== null);
+    T(copy.value === 1001);
+
+    repDoc = waitForDocPos(repDb, "foo_cont_rep_survives_doc", 3);
+    T(repDoc !== null);
+    T(repDoc.continuous === true);
+
+    // stop replication
+    T(repDb.deleteDoc(repDoc).ok);
+
+    xhr = CouchDB.request("PUT", "/_config/replicator/db", {
+      body : origRepDbName,
+      headers: {"X-Couch-Persist": "false"}
+    });
+    T(xhr.status === 200);
+  }
+
+  var server_config = [
+    {
+      section: "couch_httpd_auth",
+      key: "iterations",
+      value: "1"
+    },
+    {
+      section: "replicator",
+      key: "db",
+      value: repDb.name
+    },
+    {
+      section: "couch_httpd_auth",
+      key: "authentication_db",
+      value: usersDb.name
+    }
+  ];
+
+  repDb.deleteDb();
+  run_on_modified_server(server_config, continuous_replication_survives_restart);
+
+  // cleanup
+  repDb.deleteDb();
+  dbA.deleteDb();
+  dbB.deleteDb();
+  usersDb.deleteDb();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb/blob/92795eb2/share/www/script/test/replicator_db_swap_rep_db.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/replicator_db_swap_rep_db.js b/share/www/script/test/replicator_db_swap_rep_db.js
new file mode 100644
index 0000000..04f4e9f
--- /dev/null
+++ b/share/www/script/test/replicator_db_swap_rep_db.js
@@ -0,0 +1,170 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.replicator_db_swap_rep_db = function(debug) {
+
+  if (debug) debugger;
+
+  var populate_db = replicator_db.populate_db;
+  var docs1 = replicator_db.docs1;
+  var dbA = replicator_db.dbA;
+  var dbB = replicator_db.dbB;
+  var repDb = replicator_db.repDb;
+  var usersDb = replicator_db.usersDb;
+  var wait = replicator_db.wait;
+  var waitForRep = replicator_db.waitForRep;
+  var waitForSeq = replicator_db.waitForSeq;
+  var wait_rep_doc = replicator_db.wait_rep_doc;
+
+  function swap_rep_db() {
+    var repDb2 = new CouchDB("test_suite_rep_db_2");
+    var dbA = new CouchDB("test_suite_rep_db_a");
+    var dbA_copy = new CouchDB("test_suite_rep_db_a_copy");
+    var dbB = new CouchDB("test_suite_rep_db_b");
+    var dbB_copy = new CouchDB("test_suite_rep_db_b_copy");
+    var dbC = new CouchDB("test_suite_rep_db_c");
+    var dbC_copy = new CouchDB("test_suite_rep_db_c_copy");
+    var repDoc1, repDoc2, repDoc3;
+    var xhr, i, doc, copy, new_doc;
+
+    populate_db(dbA, docs1);
+    populate_db(dbB, docs1);
+    populate_db(dbC, docs1);
+    populate_db(dbA_copy, []);
+    populate_db(dbB_copy, []);
+    populate_db(dbC_copy, []);
+    populate_db(repDb2, []);
+
+    repDoc1 = {
+      _id: "rep1",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbA.name,
+      target: dbA_copy.name,
+      continuous: true
+    };
+    repDoc2 = {
+      _id: "rep2",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbB.name,
+      target: dbB_copy.name,
+      continuous: true
+    };
+    repDoc3 = {
+      _id: "rep3",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbC.name,
+      target: dbC_copy.name,
+      continuous: true
+    };
+
+    TEquals(true, repDb.save(repDoc1).ok);
+    TEquals(true, repDb.save(repDoc2).ok);
+
+    waitForSeq(dbA, dbA_copy);
+    waitForSeq(dbB, dbB_copy);
+
+    xhr = CouchDB.request("PUT", "/_config/replicator/db",{
+      body : JSON.stringify(repDb2.name),
+      headers: {"X-Couch-Persist": "false"}
+    });
+    TEquals(200, xhr.status);
+
+    // Temporary band-aid, give the replicator db some
+    // time to make the switch
+    wait(500);
+
+    new_doc = {
+      _id: "foo666",
+      value: 666
+    };
+
+    TEquals(true, dbA.save(new_doc).ok);
+    TEquals(true, dbB.save(new_doc).ok);
+    waitForSeq(dbA, dbA_copy);
+    waitForSeq(dbB, dbB_copy);
+
+    TEquals(true, repDb2.save(repDoc3).ok);
+    waitForSeq(dbC, dbC_copy);
+
+    for (i = 0; i < docs1.length; i++) {
+      doc = docs1[i];
+      copy = dbA_copy.open(doc._id);
+      T(copy !== null);
+      TEquals(doc.value, copy.value);
+      copy = dbB_copy.open(doc._id);
+      T(copy !== null);
+      TEquals(doc.value, copy.value);
+      copy = dbC_copy.open(doc._id);
+      T(copy !== null);
+      TEquals(doc.value, copy.value);
+    }
+
+    // replications rep1 and rep2 should have been stopped when the replicator
+    // database was swapped
+    copy = dbA_copy.open(new_doc._id);
+    TEquals(null, copy);
+    copy = dbB_copy.open(new_doc._id);
+    TEquals(null, copy);
+
+    xhr = CouchDB.request("PUT", "/_config/replicator/db",{
+      body : JSON.stringify(repDb.name),
+      headers: {"X-Couch-Persist": "false"}
+    });
+    TEquals(200, xhr.status);
+
+    // after setting the replicator database to the former, replications rep1
+    // and rep2 should have been resumed, while rep3 was stopped
+    TEquals(true, dbC.save(new_doc).ok);
+    wait(1000);
+
+    waitForSeq(dbA, dbA_copy);
+    waitForSeq(dbB, dbB_copy);
+
+    copy = dbA_copy.open(new_doc._id);
+    T(copy !== null);
+    TEquals(new_doc.value, copy.value);
+    copy = dbB_copy.open(new_doc._id);
+    T(copy !== null);
+    TEquals(new_doc.value, copy.value);
+    copy = dbC_copy.open(new_doc._id);
+    TEquals(null, copy);
+  }
+  var server_config = [
+    {
+      section: "couch_httpd_auth",
+      key: "iterations",
+      value: "1"
+    },
+    {
+      section: "replicator",
+      key: "db",
+      value: repDb.name
+    },
+    {
+      section: "couch_httpd_auth",
+      key: "authentication_db",
+      value: usersDb.name
+    }
+  ];
+
+  repDb.deleteDb();
+  run_on_modified_server(server_config, swap_rep_db);
+
+  // cleanup
+  repDb.deleteDb();
+  dbA.deleteDb();
+  dbB.deleteDb();
+  usersDb.deleteDb();
+  (new CouchDB("test_suite_rep_db_2")).deleteDb();
+  (new CouchDB("test_suite_rep_db_c")).deleteDb();
+  (new CouchDB("test_suite_rep_db_a_copy")).deleteDb();
+  (new CouchDB("test_suite_rep_db_b_copy")).deleteDb();
+  (new CouchDB("test_suite_rep_db_c_copy")).deleteDb();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb/blob/92795eb2/share/www/script/test/replicator_db_update_security.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/replicator_db_update_security.js b/share/www/script/test/replicator_db_update_security.js
new file mode 100644
index 0000000..4651514
--- /dev/null
+++ b/share/www/script/test/replicator_db_update_security.js
@@ -0,0 +1,92 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.replicator_db_update_security = function(debug) {
+
+  if (debug) debugger;
+
+  var populate_db = replicator_db.populate_db;
+  var docs1 = replicator_db.docs1;
+  var dbA = replicator_db.dbA;
+  var dbB = replicator_db.dbB;
+  var repDb = replicator_db.repDb;
+  var usersDb = replicator_db.usersDb;
+  var wait = replicator_db.wait;
+  var waitForRep = replicator_db.waitForRep;
+  var waitForSeq = replicator_db.waitForSeq;
+  var wait_rep_doc = replicator_db.wait_rep_doc;
+
+  function test_rep_db_update_security() {
+    var dbA_copy = new CouchDB("test_suite_rep_db_a_copy");
+    var dbB_copy = new CouchDB("test_suite_rep_db_b_copy");
+    var repDoc1, repDoc2;
+    var xhr, i, doc, copy, new_doc;
+    var docs = makeDocs(1, 3);
+
+    populate_db(dbA, docs);
+    populate_db(dbB, docs);
+    populate_db(dbA_copy, []);
+    populate_db(dbB_copy, []);
+
+    repDoc1 = {
+      _id: "rep1",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbA.name,
+      target: dbA_copy.name
+    };
+    repDoc2 = {
+      _id: "rep2",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbB.name,
+      target: dbB_copy.name
+    };
+
+    TEquals(true, repDb.save(repDoc1).ok);
+    waitForRep(repDb, repDoc1, "completed");
+
+    T(repDb.setSecObj({
+      readers: {
+        names: ["joe"]
+      }
+    }).ok);
+
+    TEquals(true, repDb.save(repDoc2).ok);
+    waitForRep(repDb, repDoc2, "completed");
+  }
+
+  var server_config = [
+    {
+      section: "couch_httpd_auth",
+      key: "iterations",
+      value: "1"
+    },
+    {
+      section: "replicator",
+      key: "db",
+      value: repDb.name
+    },
+    {
+      section: "couch_httpd_auth",
+      key: "authentication_db",
+      value: usersDb.name
+    }
+  ];
+
+  repDb.deleteDb();
+  run_on_modified_server(server_config, test_rep_db_update_security);
+
+  // cleanup
+  repDb.deleteDb();
+  dbA.deleteDb();
+  dbB.deleteDb();
+  usersDb.deleteDb();
+  (new CouchDB("test_suite_rep_db_a_copy")).deleteDb();
+  (new CouchDB("test_suite_rep_db_b_copy")).deleteDb();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb/blob/92795eb2/share/www/script/test/replicator_db_user_ctx.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/replicator_db_user_ctx.js b/share/www/script/test/replicator_db_user_ctx.js
new file mode 100644
index 0000000..570fc7d
--- /dev/null
+++ b/share/www/script/test/replicator_db_user_ctx.js
@@ -0,0 +1,272 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.replicator_db_user_ctx = function(debug) {
+
+  if (debug) debugger;
+
+  var populate_db = replicator_db.populate_db;
+  var docs1 = replicator_db.docs1;
+  var dbA = replicator_db.dbA;
+  var dbB = replicator_db.dbB;
+  var repDb = replicator_db.repDb;
+  var usersDb = replicator_db.usersDb;
+  var wait = replicator_db.wait;
+  var waitForRep = replicator_db.waitForRep;
+  var waitForSeq = replicator_db.waitForSeq;
+  var wait_rep_doc = replicator_db.wait_rep_doc;
+
+ function test_user_ctx_validation() {
+    populate_db(dbA, docs1);
+    populate_db(dbB, []);
+    populate_db(usersDb, []);
+
+    var joeUserDoc = CouchDB.prepareUserDoc({
+      name: "joe",
+      roles: ["erlanger", "bar"]
+    }, "erly");
+    var fdmananaUserDoc = CouchDB.prepareUserDoc({
+      name: "fdmanana",
+      roles: ["a", "b", "c"]
+    }, "qwerty");
+
+    TEquals(true, usersDb.save(joeUserDoc).ok);
+    TEquals(true, usersDb.save(fdmananaUserDoc).ok);
+
+    T(dbB.setSecObj({
+      admins: {
+        names: [],
+        roles: ["god"]
+      },
+      readers: {
+        names: [],
+        roles: ["foo"]
+      }
+    }).ok);
+
+    TEquals(true, CouchDB.login("joe", "erly").ok);
+    TEquals("joe", CouchDB.session().userCtx.name);
+    TEquals(-1, CouchDB.session().userCtx.roles.indexOf("_admin"));
+
+    var repDoc = {
+      _id: "foo_rep",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbA.name,
+      target: dbB.name
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "Should have failed, user_ctx missing.");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc.user_ctx = {
+      name: "john",
+      roles: ["erlanger"]
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "Should have failed, wrong user_ctx.name.");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    repDoc.user_ctx = {
+      name: "joe",
+      roles: ["bar", "god", "erlanger"]
+    };
+
+    try {
+      repDb.save(repDoc);
+      T(false, "Should have failed, a bad role in user_ctx.roles.");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    // user_ctx.roles might contain only a subset of the user's roles
+    repDoc.user_ctx = {
+      name: "joe",
+      roles: ["erlanger"]
+    };
+
+    TEquals(true, repDb.save(repDoc).ok);
+    CouchDB.logout();
+
+    waitForRep(repDb, repDoc, "error");
+    var repDoc1 = repDb.open(repDoc._id);
+    T(repDoc1 !== null);
+    TEquals(repDoc.source, repDoc1.source);
+    TEquals(repDoc.target, repDoc1.target);
+    TEquals("error", repDoc1._replication_state);
+    TEquals("string", typeof repDoc1._replication_id);
+    TEquals("string", typeof repDoc1._replication_state_time);
+
+    TEquals(true, CouchDB.login("fdmanana", "qwerty").ok);
+    TEquals("fdmanana", CouchDB.session().userCtx.name);
+    TEquals(-1, CouchDB.session().userCtx.roles.indexOf("_admin"));
+
+    try {
+      T(repDb.deleteDoc(repDoc1).ok);
+      T(false, "Shouldn't be able to delete replication document.");
+    } catch (x) {
+      TEquals("forbidden", x.error);
+    }
+
+    CouchDB.logout();
+    TEquals(true, CouchDB.login("joe", "erly").ok);
+    TEquals("joe", CouchDB.session().userCtx.name);
+    TEquals(-1, CouchDB.session().userCtx.roles.indexOf("_admin"));
+
+    T(repDb.deleteDoc(repDoc1).ok);
+    CouchDB.logout();
+
+    for (var i = 0; i < docs1.length; i++) {
+      var doc = docs1[i];
+      var copy = dbB.open(doc._id);
+
+      TEquals(null, copy);
+    }
+
+    T(dbB.setSecObj({
+      admins: {
+        names: [],
+        roles: ["god", "erlanger"]
+      },
+      readers: {
+        names: [],
+        roles: ["foo"]
+      }
+    }).ok);
+
+    TEquals(true, CouchDB.login("joe", "erly").ok);
+    TEquals("joe", CouchDB.session().userCtx.name);
+    TEquals(-1, CouchDB.session().userCtx.roles.indexOf("_admin"));
+
+    repDoc = {
+      _id: "foo_rep_2",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbA.name,
+      target: dbB.name,
+      user_ctx: {
+        name: "joe",
+        roles: ["erlanger"]
+      }
+    };
+
+    TEquals(true, repDb.save(repDoc).ok);
+    CouchDB.logout();
+
+    waitForRep(repDb, repDoc, "complete");
+    repDoc1 = repDb.open(repDoc._id);
+    T(repDoc1 !== null);
+    TEquals(repDoc.source, repDoc1.source);
+    TEquals(repDoc.target, repDoc1.target);
+    TEquals("completed", repDoc1._replication_state);
+    TEquals("string", typeof repDoc1._replication_id);
+    TEquals("string", typeof repDoc1._replication_state_time);
+
+    for (var i = 0; i < docs1.length; i++) {
+      var doc = docs1[i];
+      var copy = dbB.open(doc._id);
+
+      T(copy !== null);
+      TEquals(doc.value, copy.value);
+    }
+
+    // Admins don't need to supply a user_ctx property in replication docs.
+    // If they do not, the implicit user_ctx "user_ctx": {name: null, roles: []}
+    // is used, meaning that design documents will not be replicated into
+    // local targets
+    T(dbB.setSecObj({
+      admins: {
+        names: [],
+        roles: []
+      },
+      readers: {
+        names: [],
+        roles: []
+      }
+    }).ok);
+
+    var ddoc = { _id: "_design/foo" };
+    TEquals(true, dbA.save(ddoc).ok);
+
+    repDoc = {
+      _id: "foo_rep_3",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbA.name,
+      target: dbB.name
+    };
+
+    TEquals(true, repDb.save(repDoc).ok);
+    waitForRep(repDb, repDoc, "complete");
+    repDoc1 = repDb.open(repDoc._id);
+    T(repDoc1 !== null);
+    TEquals(repDoc.source, repDoc1.source);
+    TEquals(repDoc.target, repDoc1.target);
+    TEquals("completed", repDoc1._replication_state);
+    TEquals("string", typeof repDoc1._replication_id);
+    TEquals("string", typeof repDoc1._replication_state_time);
+
+    var ddoc_copy = dbB.open(ddoc._id);
+    T(ddoc_copy === null);
+
+    repDoc = {
+      _id: "foo_rep_4",
+      source: CouchDB.protocol + CouchDB.host + "/" + dbA.name,
+      target: dbB.name,
+      user_ctx: {
+        roles: ["_admin"]
+      }
+    };
+
+    TEquals(true, repDb.save(repDoc).ok);
+    waitForRep(repDb, repDoc, "complete");
+    repDoc1 = repDb.open(repDoc._id);
+    T(repDoc1 !== null);
+    TEquals(repDoc.source, repDoc1.source);
+    TEquals(repDoc.target, repDoc1.target);
+    TEquals("completed", repDoc1._replication_state);
+    TEquals("string", typeof repDoc1._replication_id);
+    TEquals("string", typeof repDoc1._replication_state_time);
+
+    ddoc_copy = dbB.open(ddoc._id);
+    T(ddoc_copy !== null);
+  }
+
+  var server_config = [
+    {
+      section: "couch_httpd_auth",
+      key: "iterations",
+      value: "1"
+    },
+    {
+      section: "replicator",
+      key: "db",
+      value: repDb.name
+    },
+    {
+      section: "couch_httpd_auth",
+      key: "authentication_db",
+      value: usersDb.name
+    }
+  ];
+
+  repDb.deleteDb();
+  run_on_modified_server(server_config, test_user_ctx_validation);
+
+  // cleanup
+  repDb.deleteDb();
+  dbA.deleteDb();
+  dbB.deleteDb();
+  usersDb.deleteDb();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb/blob/92795eb2/share/www/script/test/replicator_db_write_auth.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/replicator_db_write_auth.js b/share/www/script/test/replicator_db_write_auth.js
new file mode 100644
index 0000000..697abf3
--- /dev/null
+++ b/share/www/script/test/replicator_db_write_auth.js
@@ -0,0 +1,102 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.replicator_db_survives = function(debug) {
+
+  if (debug) debugger;
+
+  var populate_db = replicator_db.populate_db;
+  var docs1 = replicator_db.docs1;
+  var dbA = replicator_db.dbA;
+  var dbB = replicator_db.dbB;
+  var repDb = replicator_db.repDb;
+  var usersDb = replicator_db.usersDb;
+  var wait = replicator_db.wait;
+  var waitForRep = replicator_db.waitForRep;
+  var waitForSeq = replicator_db.waitForSeq;
+  var waitForDocPos = replicator_db.waitForDocPos;
+  var wait_rep_doc = replicator_db.wait_rep_doc;
+
+  function rep_db_write_authorization() {
+    populate_db(dbA, docs1);
+    populate_db(dbB, []);
+
+    var server_admins_config = [
+      {
+        section: "admins",
+        key: "fdmanana",
+        value: "qwerty"
+      }
+    ];
+
+    run_on_modified_server(server_admins_config, function() {
+      var repDoc = {
+        _id: "foo_rep_doc",
+        source: dbA.name,
+        target: dbB.name,
+        continuous: true
+      };
+
+      T(CouchDB.login("fdmanana", "qwerty").ok);
+      T(CouchDB.session().userCtx.name === "fdmanana");
+      T(CouchDB.session().userCtx.roles.indexOf("_admin") !== -1);
+
+      T(repDb.save(repDoc).ok);
+
+      waitForRep(repDb, repDoc, "completed");
+
+      for (var i = 0; i < docs1.length; i++) {
+        var doc = docs1[i];
+        var copy = dbB.open(doc._id);
+
+        T(copy !== null);
+        T(copy.value === doc.value);
+      }
+
+      repDoc = repDb.open("foo_rep_doc");
+      T(repDoc !== null);
+      repDoc.target = "test_suite_foo_db";
+      repDoc.create_target = true;
+
+      // Only the replicator can update replication documents.
+      // Admins can only add and delete replication documents.
+      try {
+        repDb.save(repDoc);
+        T(false && "Should have thrown an exception");
+      } catch (x) {
+        T(x["error"] === "forbidden");
+      }
+    });
+  }
+
+  var server_config = [
+    {
+      section: "couch_httpd_auth",
+      key: "iterations",
+      value: "1"
+    },
+    {
+      section: "replicator",
+      key: "db",
+      value: repDb.name
+    }
+  ];
+
+  repDb.deleteDb();
+  run_on_modified_server(server_config, rep_db_write_authorization);
+
+  // cleanup
+  repDb.deleteDb();
+  dbA.deleteDb();
+  dbB.deleteDb();
+  usersDb.deleteDb();
+}
\ No newline at end of file


Mime
View raw message