Merge branch '1843-feature-bigcouch'
diff --git a/script/couch.js b/script/couch.js
index 3deb441..122db75 100644
--- a/script/couch.js
+++ b/script/couch.js
@@ -36,7 +36,7 @@
 
   // Deletes the database on the server
   this.deleteDb = function() {
-    this.last_req = this.request("DELETE", this.uri);
+    this.last_req = this.request("DELETE", this.uri + "?sync=true");
     if (this.last_req.status == 404) {
       return false;
     }
@@ -356,6 +356,12 @@
   return JSON.parse(CouchDB.last_req.responseText).version;
 };
 
+CouchDB.reloadConfig = function() {
+  CouchDB.last_req = CouchDB.request("POST", "/_config/_reload");
+  CouchDB.maybeThrowError(CouchDB.last_req);
+  return JSON.parse(CouchDB.last_req.responseText);
+};
+
 CouchDB.replicate = function(source, target, rep_options) {
   rep_options = rep_options || {};
   var headers = rep_options.headers || {};
diff --git a/script/couch_test_runner.js b/script/couch_test_runner.js
index 7f435bf..efc4dc2 100644
--- a/script/couch_test_runner.js
+++ b/script/couch_test_runner.js
@@ -417,40 +417,35 @@
   }
 }
 
-function waitForRestart() {
-  var waiting = true;
-  // Wait for the server to go down but don't
-  // wait too long because we might miss the
-  // the unavailable period.
-  var count = 25;
-  while (waiting && count > 0) {
-    count--;
-    try {
-      CouchDB.request("GET", "/");
-    } catch(e) {
-      waiting = false;
-    }
-  }
-  // Wait for it to come back up
-  waiting = true;
-  while (waiting) {
-    try {
-      CouchDB.request("GET", "/");
-      waiting = false;
-    } catch(e) {
-      // the request will fail until restart completes
-    }
-  }
+function getCurrentToken() {
+  var xhr = CouchDB.request("GET", "/_restart/token");
+  return JSON.parse(xhr.responseText).token;
 };
 
+
 function restartServer() {
-  var xhr;
-  try {
-    CouchDB.request("POST", "/_restart");
-  } catch(e) {
-    // this request may sometimes fail
+  var token = getCurrentToken();
+  var token_changed = false;
+  var tDelta = 5000;
+  var t0 = new Date();
+  var t1;
+
+  CouchDB.request("POST", "/_restart");
+
+  do {
+    try {
+      if(token != getCurrentToken()) {
+        token_changed = true;
+      }
+    } catch (e) {
+      // Ignore errors while the server restarts
+    }
+    t1 = new Date();
+  } while(((t1 - t0) <= tDelta) && !token_changed);
+
+  if(!token_changed) {
+    throw("Server restart failed");
   }
-  waitForRestart();
 }
 
 // legacy functions for CouchDB < 1.2.0
diff --git a/script/futon.browse.js b/script/futon.browse.js
index 241164c..df4e3d8 100644
--- a/script/futon.browse.js
+++ b/script/futon.browse.js
@@ -93,7 +93,7 @@
                   $("#databases tbody.content tr:eq(" + idx + ")")
                     .find("td.size").text($.futon.formatSize(info.disk_size)).end()
                     .find("td.count").text(info.doc_count).end()
-                    .find("td.seq").text(info.update_seq);
+                    .find("td.seq").text(info.update_seq.split("-")[0]);
                 },
                 error : function() {}
               });
@@ -131,7 +131,7 @@
       var urlParts = location.search.substr(1).split("/");
       var dbName = decodeURIComponent(urlParts.shift())
 
-      var dbNameRegExp = new RegExp("[^a-z0-9\_\$\(\)\+\/\-]", "g");
+      var dbNameRegExp = new RegExp("[^a-z0-9.\_\$\(\)\+\/\-]", "g");
       dbName = dbName.replace(dbNameRegExp, "");
 
       $.futon.storage.declareWithPrefix(dbName + ".", {
diff --git a/script/test/erlang_views.js b/script/test/erlang_views.js
index 7eddab4..c6bc5d7 100644
--- a/script/test/erlang_views.js
+++ b/script/test/erlang_views.js
@@ -44,7 +44,10 @@
       // check simple reduction - another doc with same key.
       var doc = {_id: "2", integer: 1, string: "str2"};
       T(db.save(doc).ok);
-      rfun = "fun(Keys, Values, ReReduce) -> length(Values) end.";
+      rfun = 'fun' +
+              ' (_, Values, false) -> length(Values); ' +
+              ' (_, Values, true) -> lists:sum(Values) ' +
+              ' end.';
       results = db.query(mfun, rfun, null, null, "erlang");
       T(results.rows[0].value == 2);
 
diff --git a/script/test/oauth.js b/script/test/oauth.js
index 9199cd0..8b4e694 100644
--- a/script/test/oauth.js
+++ b/script/test/oauth.js
@@ -23,12 +23,14 @@
   var dbA = new CouchDB("test_suite_db_a", {"X-Couch-Full-Commit":"false"});
   var dbB = new CouchDB("test_suite_db_b", {"X-Couch-Full-Commit":"false"});
   var dbC = new CouchDB("test_suite_db_c", {"X-Couch-Full-Commit":"false"});
+  var dbD = new CouchDB("test_suite_users", {"X-Couch-Full-Commit":"false"});
   dbA.deleteDb();
   dbA.createDb();
   dbB.deleteDb();
   dbB.createDb();
   dbC.deleteDb();
   dbC.createDb();
+  dbD.deleteDb();
 
   // Simple secret key generator
   function generateSecret(length) {
@@ -125,7 +127,6 @@
         "X-Couch-Full-Commit":"false",
         "Authorization": adminBasicAuthHeaderValue()
       });
-      usersDb.deleteDb();
         
       // Create a user
       var jasonUserDoc = CouchDB.prepareUserDoc({
diff --git a/script/test/proxyauth.js b/script/test/proxyauth.js
index 016cec5..1677a66 100644
--- a/script/test/proxyauth.js
+++ b/script/test/proxyauth.js
@@ -19,7 +19,9 @@
   var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
   
   if (debug) debugger;
-  
+ 
+  usersDb.deleteDb();
+
   // Simple secret key generator
   function generateSecret(length) {
     var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -33,7 +35,6 @@
   var secret = generateSecret(64);
   
   function TestFun() {
-    usersDb.deleteDb();
     db.deleteDb();
     db.createDb();
     
@@ -126,4 +127,4 @@
     TestFun
   );
   
-};
\ No newline at end of file
+};
diff --git a/script/test/replication.js b/script/test/replication.js
index fd60dd4..7e4ecc1 100644
--- a/script/test/replication.js
+++ b/script/test/replication.js
@@ -1359,17 +1359,24 @@
   TEquals(true, repResult.ok);
   TEquals('string', typeof repResult._local_id);
 
-  var xhr = CouchDB.request("GET", "/_active_tasks");
-  var tasks = JSON.parse(xhr.responseText);
-
   TEquals(true, sourceDb.compact().ok);
   while (sourceDb.info().compact_running) {};
 
   TEquals(true, sourceDb.save(makeDocs(30, 31)[0]).ok);
   xhr = CouchDB.request("GET", "/_active_tasks");
 
-  var tasksAfter = JSON.parse(xhr.responseText);
-  TEquals(tasks.length, tasksAfter.length);
+  var xhr = CouchDB.request("GET", "/_active_tasks");
+  var tasks = JSON.parse(xhr.responseText);
+
+  var found_task = false;
+  for(var i = 0; i < tasks.length; i++) {
+    if(tasks[i].replication_id == repResult._local_id) {
+      found_task = true;
+      break;
+    }
+  }
+  TEquals(true, found_task);
+
   waitForSeq(sourceDb, targetDb);
   T(sourceDb.open("30") !== null);
 
@@ -1695,6 +1702,9 @@
   TEquals(true, repResult.ok);
   TEquals('string', typeof repResult._local_id);
 
+  // Race conditions are awesome
+  wait(500);
+
   xhr = CouchDB.request("GET", "/_active_tasks");
   tasks = JSON.parse(xhr.responseText);
 
diff --git a/script/test/security_validation.js b/script/test/security_validation.js
index 862924a..14e5d04 100644
--- a/script/test/security_validation.js
+++ b/script/test/security_validation.js
@@ -115,6 +115,8 @@
         {"WWW-Authenticate": "X-Couch-Test-Auth Jan Lehnardt:apple"}
       );
       // Attempt to save the design as a non-admin (in replication scenario)
+      designDoc.foo = "bar";
+      designDoc._rev = "2-642e20f96624a0aae6025b4dba0c6fb2";
       try {
         user2Db.save(designDoc, {new_edits : false});
         T(false && "Can't get here. Should have thrown an error on design doc");
diff --git a/script/test/show_documents.js b/script/test/show_documents.js
index d4c8ac4..618925f 100644
--- a/script/test/show_documents.js
+++ b/script/test/show_documents.js
@@ -409,7 +409,7 @@
 
       function() {
         T(db.setDbProperty("_security", {foo: true}).ok);
-        T(db.save(doc).ok);
+        T(db.save({_id:"testdoc",foo:1}).ok);
 
         xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/secObj");
         var resp = JSON.parse(xhr.responseText);
diff --git a/script/test/users_db_security.js b/script/test/users_db_security.js
index 2a2bb9d..f2ca8bc 100644
--- a/script/test/users_db_security.js
+++ b/script/test/users_db_security.js
@@ -79,7 +79,6 @@
 
   var testFun = function()
   {
-    usersDb.deleteDb();
 
     // _users db
     // a doc with a field 'password' should be hashed to 'derived_key'
diff --git a/script/test/view_compaction.js b/script/test/view_compaction.js
index 151ce93..35d6276 100644
--- a/script/test/view_compaction.js
+++ b/script/test/view_compaction.js
@@ -27,7 +27,7 @@
         map: "function(doc) { emit(doc._id, doc.value) }"
       },
       view2: {
-        map: "function(doc) { emit(doc._id, doc.value); }",
+        map: "function(doc) { if (typeof(doc.integer) === 'number') {emit(doc._id, doc.integer);} }",
         reduce: "function(keys, values, rereduce) { return sum(values); }"
       }
     }
@@ -38,13 +38,13 @@
   db.bulkSave(docs);
 
   var resp = db.view('foo/view1', {});
-  T(resp.rows.length === 10000);
+  TEquals(10000, resp.rows.length);
 
   resp = db.view('foo/view2', {});
-  T(resp.rows.length === 1);
+  TEquals(1, resp.rows.length);
 
   resp = db.designInfo("_design/foo");
-  T(resp.view_index.update_seq === 10001);
+  TEquals(10001, resp.view_index.update_seq);
 
 
   // update docs
@@ -55,13 +55,13 @@
 
 
   resp = db.view('foo/view1', {});
-  T(resp.rows.length === 10000);
+  TEquals(10000, resp.rows.length);
 
   resp = db.view('foo/view2', {});
-  T(resp.rows.length === 1);
+  TEquals(1, resp.rows.length);
 
   resp = db.designInfo("_design/foo");
-  T(resp.view_index.update_seq === 20001);
+  TEquals(20001, resp.view_index.update_seq);
 
 
   // update docs again...
@@ -72,13 +72,13 @@
 
 
   resp = db.view('foo/view1', {});
-  T(resp.rows.length === 10000);
+  TEquals(10000, resp.rows.length);
 
   resp = db.view('foo/view2', {});
-  T(resp.rows.length === 1);
+  TEquals(1, resp.rows.length);
 
   resp = db.designInfo("_design/foo");
-  T(resp.view_index.update_seq === 30001);
+  TEquals(30001, resp.view_index.update_seq);
 
   var disk_size_before_compact = resp.view_index.disk_size;
   var data_size_before_compact = resp.view_index.data_size;
@@ -97,13 +97,13 @@
 
 
   resp = db.view('foo/view1', {});
-  T(resp.rows.length === 10000);
+  TEquals(10000, resp.rows.length);
 
   resp = db.view('foo/view2', {});
-  T(resp.rows.length === 1);
+  TEquals(1, resp.rows.length);
 
   resp = db.designInfo("_design/foo");
-  T(resp.view_index.update_seq === 30001);
+  TEquals(30001, resp.view_index.update_seq);
   T(resp.view_index.disk_size < disk_size_before_compact);
   TEquals("number", typeof resp.view_index.data_size, "data size is a number");
   T(resp.view_index.data_size < resp.view_index.disk_size, "data size < file size");
diff --git a/script/test/view_include_docs.js b/script/test/view_include_docs.js
index 944c910..dab79b8 100644
--- a/script/test/view_include_docs.js
+++ b/script/test/view_include_docs.js
@@ -33,7 +33,7 @@
         map: "function(doc) {if(doc.link_id) { var value = {'_id':doc.link_id}; if (doc.link_rev) {value._rev = doc.link_rev}; emit(doc._id, value);}};"
       },
       summate: {
-        map:"function (doc) {emit(doc.integer, doc.integer)};",
+        map:"function (doc) { if (typeof doc.integer === 'number') {emit(doc.integer, doc.integer)};}",
         reduce:"function (keys, values) { return sum(values); };"
       }
     }
diff --git a/script/test/view_update_seq.js b/script/test/view_update_seq.js
index 69b8c42..df92b11 100644
--- a/script/test/view_update_seq.js
+++ b/script/test/view_update_seq.js
@@ -31,7 +31,7 @@
         map: "function(doc) { emit(doc.integer, doc.string) }"
       },
       summate: {
-        map:"function (doc) {emit(doc.integer, doc.integer)};",
+        map:"function (doc) { if (typeof doc.integer === 'number') { emit(doc.integer, doc.integer)}; }",
         reduce:"function (keys, values) { return sum(values); };"
       }
     }
@@ -68,12 +68,12 @@
   T(resp.rows.length == 1);
   T(resp.update_seq == 101);
 
-  db.save({"id":"0"});
+  db.save({"id":"0", "integer": 1});
   resp = db.view('test/all_docs', {limit: 1,stale: "ok", update_seq:true});
   T(resp.rows.length == 1);
   T(resp.update_seq == 101);
 
-  db.save({"id":"00"});
+  db.save({"id":"00", "integer": 2});
   resp = db.view('test/all_docs',
     {limit: 1, stale: "update_after", update_seq: true});
   T(resp.rows.length == 1);
@@ -100,7 +100,7 @@
   resp = db.view('test/all_docs',{update_seq:true},["0","1"]);
   T(resp.update_seq == 103);
 
-  resp = db.view('test/summate',{group:true, update_seq:true},["0","1"]);
-  T(resp.update_seq == 103);
+  resp = db.view('test/summate',{group:true, update_seq:true},[0,1]);
+  TEquals(103, resp.update_seq);
 
 };