You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ja...@apache.org on 2018/01/31 13:10:53 UTC

[couchdb] 01/02: Fix for issue #603 - Error 500 when creating a db below quorum

This is an automated email from the ASF dual-hosted git repository.

jan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 960a6f9dcca7ece74838e377b091050284a3233a
Author: Juanjo <ju...@localhost.localdomain>
AuthorDate: Wed Jan 24 15:01:40 2018 +0100

    Fix for issue #603 - Error 500 when creating a db below quorum
    
    Add degrade-cluster option for cluster testing
    
    Add tests for different cluster conditions with/without quorum
    
    Add test-cluster-with-quorum and test-cluster-without-quorum tasks
---
 Makefile                                           | 34 ++++++++++++++++++++++
 dev/run                                            | 24 +++++++++++++--
 src/fabric/src/fabric_db_create.erl                |  4 +--
 test/javascript/run                                | 16 +++++-----
 .../tests-cluster/with-quorum/db-creation.js       | 27 +++++++++++++++++
 .../tests-cluster/without-quorum/db-creation.js    | 28 ++++++++++++++++++
 6 files changed, 122 insertions(+), 11 deletions(-)

diff --git a/Makefile b/Makefile
index c8c0b09..05a1f39 100644
--- a/Makefile
+++ b/Makefile
@@ -129,6 +129,40 @@ endif
             'test/javascript/run --suites "$(suites)" \
             --ignore "$(ignore_js_suites)"'
 
+.PHONY: test-cluster-with-quorum
+test-cluster-with-quorum:
+	@mkdir -p share/www/script/test
+ifeq ($(IN_RELEASE), true)
+	@cp test/javascript/tests/lorem*.txt share/www/script/test/
+else
+	@mkdir -p src/fauxton/dist/release/test
+	@cp test/javascript/tests/lorem*.txt src/fauxton/dist/release/test/
+endif
+	@rm -rf dev/lib
+	@dev/run -n 3 -q --with-admin-party-please \
+            --enable-erlang-views --degrade-cluster 1 \
+            -c 'startup_jitter=0' \
+            'test/javascript/run --suites "$(suites)" \
+            --ignore "$(ignore_js_suites)" \
+	    --path test/javascript/tests-cluster/with-quorum'
+
+.PHONY: test-cluster-without-quorum
+test-cluster-without-quorum:
+	@mkdir -p share/www/script/test
+ifeq ($(IN_RELEASE), true)
+	@cp test/javascript/tests/lorem*.txt share/www/script/test/
+else
+	@mkdir -p src/fauxton/dist/release/test
+	@cp test/javascript/tests/lorem*.txt src/fauxton/dist/release/test/
+endif
+	@rm -rf dev/lib
+	@dev/run -n 3 -q --with-admin-party-please \
+            --enable-erlang-views --degrade-cluster 2 \
+            -c 'startup_jitter=0' \
+            'test/javascript/run --suites "$(suites)" \
+            --ignore "$(ignore_js_suites)" \
+            --path test/javascript/tests-cluster/without-quorum'
+
 .PHONY: soak-javascript
 soak-javascript:
 	@mkdir -p share/www/script/test
diff --git a/dev/run b/dev/run
index 4924de1..a5d8fde 100755
--- a/dev/run
+++ b/dev/run
@@ -130,6 +130,8 @@ def setup_argparse():
                       help='The node number to seed them when creating the node(s)')
     parser.add_option('-c', '--config-overrides', action="append", default=[],
                       help='Optional key=val config overrides. Can be repeated')
+    parser.add_option('--degrade-cluster', dest="degrade_cluster",type=int, default=0,
+                      help='The number of nodes that should be stopped after cluster config')
     return parser.parse_args()
 
 
@@ -142,6 +144,7 @@ def setup_context(opts, args):
             'admin': opts.admin.split(':', 1) if opts.admin else None,
             'nodes': ['node%d' % (i + opts.node_number) for i in range(opts.nodes)],
             'node_number': opts.node_number,
+            'degrade_cluster': opts.degrade_cluster,
             'devdir': os.path.dirname(fpath),
             'rootdir': os.path.dirname(os.path.dirname(fpath)),
             'cmd': ' '.join(args),
@@ -337,18 +340,35 @@ def startup(ctx):
         cluster_setup_with_admin_party(ctx)
     else:
         cluster_setup(ctx)
-
+    if ctx['degrade_cluster'] > 0:
+        degrade_cluster(ctx)
 
 def kill_processes(ctx):
     for proc in ctx['procs']:
         if proc and proc.returncode is None:
             proc.kill()
 
+def degrade_cluster(ctx):
+    if ctx['with_haproxy']:
+        haproxy_proc = ctx['procs'].pop()
+    for i in range(0,ctx['degrade_cluster']):
+        proc = ctx['procs'].pop()
+        if proc is not None:
+            kill_process(proc)
+    if ctx['with_haproxy']:
+         ctx['procs'].append(haproxy_proc)
+
+@log('Stoping proc {proc.pid}')
+def kill_process(proc):
+    if proc and proc.returncode is None:
+        proc.kill()
 
 def boot_nodes(ctx):
     for node in ctx['nodes']:
         ctx['procs'].append(boot_node(ctx, node))
-    ctx['procs'].append(boot_haproxy(ctx))
+    haproxy_proc = boot_haproxy(ctx)
+    if haproxy_proc is not None:
+        ctx['procs'].append(haproxy_proc)
 
 
 def ensure_all_nodes_alive(ctx):
diff --git a/src/fabric/src/fabric_db_create.erl b/src/fabric/src/fabric_db_create.erl
index d793f4f..db914f9 100644
--- a/src/fabric/src/fabric_db_create.erl
+++ b/src/fabric/src/fabric_db_create.erl
@@ -146,9 +146,9 @@ maybe_stop(W, Counters) ->
         {ok, {W, Counters}};
     false ->
         case lists:sum([1 || {_, ok} <- Counters]) of
-        W ->
+        NumOk when NumOk >= (W div 2 +1) ->
             {stop, ok};
-        NumOk when NumOk >= (W div 2 + 1) ->
+        NumOk when NumOk > 0 ->
             {stop, accepted};
         _ ->
             {error, internal_server_error}
diff --git a/test/javascript/run b/test/javascript/run
index c611be5..8ae4244 100755
--- a/test/javascript/run
+++ b/test/javascript/run
@@ -107,7 +107,10 @@ def options():
                        dest="ignore", help="Ignore test suites"),
         op.make_option("-u", "--suites", type="string", action="callback",
                        default=None, callback=get_delimited_list,
-                       dest="suites", help="Run specific suites")
+                       dest="suites", help="Run specific suites"),
+        op.make_option("-p", "--path", type="string",
+                       default="test/javascript/tests",
+                       dest="test_path", help="Path where the tests are located")
     ]
 
 
@@ -118,10 +121,9 @@ def main():
     run_list = []
     ignore_list = []
     tests = []
-
-    run_list = ["test/javascript/tests"] if not opts.suites else opts.suites
-    run_list = build_test_case_paths(run_list)
-    ignore_list = build_test_case_paths(opts.ignore)
+    run_list = [opts.test_path] if not opts.suites else opts.suites
+    run_list = build_test_case_paths(opts.test_path,run_list)
+    ignore_list = build_test_case_paths(opts.test_path,opts.ignore)
     # sort is needed because certain tests fail if executed out of order
     tests = sorted(list(set(run_list)-set(ignore_list)))
 
@@ -151,7 +153,7 @@ def main():
         failed, passed) + os.linesep)
     exit(failed > 0)
 
-def build_test_case_paths(args=None):
+def build_test_case_paths(path,args=None):
     tests = []
     if args is None:
         args = []
@@ -161,7 +163,7 @@ def build_test_case_paths(args=None):
         elif os.path.isfile(name):
             check = tests.append(name)
         else:
-            pname = os.path.join("test/javascript/tests", name)
+            pname = os.path.join(path, name)
             if os.path.isfile(pname):
                 tests.append(pname)
             elif os.path.isfile(pname + ".js"):
diff --git a/test/javascript/tests-cluster/with-quorum/db-creation.js b/test/javascript/tests-cluster/with-quorum/db-creation.js
new file mode 100644
index 0000000..f8efd6e
--- /dev/null
+++ b/test/javascript/tests-cluster/with-quorum/db-creation.js
@@ -0,0 +1,27 @@
+// 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.
+
+// Do DB creation under cluster with quorum conditions.
+couchTests.db_creation = function(debug) {
+
+  if (debug) debugger;
+
+  var db_name = get_random_db_name()
+  var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"});
+
+  // DB Creation should return 201 - Created
+  xhr = CouchDB.request("PUT", "/" + db_name + "/");
+  T(xhr.status == 201);
+
+  // cleanup
+  db.deleteDb();
+};
diff --git a/test/javascript/tests-cluster/without-quorum/db-creation.js b/test/javascript/tests-cluster/without-quorum/db-creation.js
new file mode 100644
index 0000000..0d8ff83
--- /dev/null
+++ b/test/javascript/tests-cluster/without-quorum/db-creation.js
@@ -0,0 +1,28 @@
+// 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.
+
+// Do DB creation under cluster without quorum conditions.
+couchTests.db_creation = function(debug) {
+
+  if (debug) debugger;
+
+  var db_name = get_random_db_name()
+  var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"});
+
+  // DB Creation should return 202- Accepted
+  xhr = CouchDB.request("PUT", "/" + db_name + "/");
+  T(xhr.status == 202);
+
+  // cleanup
+  // TODO DB deletions fails if the quorum is not met.
+  xhr = CouchDB.request("DELETE", "/" + db_name + "/");
+};

-- 
To stop receiving notification emails like this one, please contact
jan@apache.org.