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

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


The following commit(s) were added to refs/heads/master by this push:
     new cb3c772  Port design_docs tests from js to elixir (#2641)
cb3c772 is described below

commit cb3c7723cc877890c810f4e2b4d10326bdb3e72c
Author: Juanjo Rodriguez <[email protected]>
AuthorDate: Thu Mar 19 21:27:30 2020 +0100

    Port design_docs tests from js to elixir (#2641)
---
 test/elixir/README.md                 |   2 +-
 test/elixir/test/design_docs_test.exs | 479 ++++++++++++++++++++++++++++++++++
 test/javascript/tests/design_docs.js  |   2 +
 3 files changed, 482 insertions(+), 1 deletion(-)

diff --git a/test/elixir/README.md b/test/elixir/README.md
index 2806cfb..53b56a2 100644
--- a/test/elixir/README.md
+++ b/test/elixir/README.md
@@ -42,7 +42,7 @@ X means done, - means partially
   - [X] Port conflicts.js
   - [X] Port cookie_auth.js
   - [X] Port copy_doc.js
-  - [ ] Port design_docs.js
+  - [X] Port design_docs.js
   - [X] Port design_docs_query.js
   - [X] Port design_options.js
   - [X] Port design_paths.js
diff --git a/test/elixir/test/design_docs_test.exs 
b/test/elixir/test/design_docs_test.exs
new file mode 100644
index 0000000..258f5f7
--- /dev/null
+++ b/test/elixir/test/design_docs_test.exs
@@ -0,0 +1,479 @@
+defmodule DesignDocsTest do
+  use CouchTestCase
+
+  @moduletag :design_docs
+
+  @design_doc %{
+    _id: "_design/test",
+    language: "javascript",
+    autoupdate: false,
+    whatever: %{
+      stringzone: "exports.string = 'plankton';",
+      commonjs: %{
+        whynot: """
+        exports.test = require('../stringzone');
+        exports.foo = require('whatever/stringzone');
+        """,
+        upper: """
+        exports.testing = require('./whynot').test.string.toUpperCase()+
+        module.id+require('./whynot').foo.string
+        """,
+        circular_one: "require('./circular_two'); exports.name = 'One';",
+        circular_two: "require('./circular_one'); exports.name = 'Two';"
+      },
+      # paths relative to parent
+      idtest1: %{
+        a: %{
+          b: %{d: "module.exports = require('../c/e').id;"},
+          c: %{e: "exports.id = module.id;"}
+        }
+      },
+      # multiple paths relative to parent
+      idtest2: %{
+        a: %{
+          b: %{d: "module.exports = require('../../a/c/e').id;"},
+          c: %{e: "exports.id = module.id;"}
+        }
+      },
+      # paths relative to module
+      idtest3: %{
+        a: %{
+          b: "module.exports = require('./c/d').id;",
+          c: %{
+            d: "module.exports = require('./e');",
+            e: "exports.id = module.id;"
+          }
+        }
+      },
+      # paths relative to module and parent
+      idtest4: %{
+        a: %{
+          b: "module.exports = require('../a/./c/d').id;",
+          c: %{
+            d: "module.exports = require('./e');",
+            e: "exports.id = module.id;"
+          }
+        }
+      },
+      # paths relative to root
+      idtest5: %{
+        a: "module.exports = require('whatever/idtest5/b').id;",
+        b: "exports.id = module.id;"
+      }
+    },
+    views: %{
+      all_docs_twice: %{
+        map: """
+        function(doc) {
+          emit(doc.integer, null);
+          emit(doc.integer, null);
+        }
+        """
+      },
+      no_docs: %{
+        map: """
+        function(doc) {}
+        """
+      },
+      single_doc: %{
+        map: """
+        function(doc) {
+          if (doc._id === "1") {
+            emit(1, null);
+          }
+        }
+        """
+      },
+      summate: %{
+        map: """
+        function(doc) {
+          emit(doc.integer, doc.integer);
+        }
+        """,
+        reduce: """
+        function(keys, values) {
+          return sum(values);
+        }
+        """
+      },
+      summate2: %{
+        map: """
+        function(doc) {
+          emit(doc.integer, doc.integer);
+        }
+        """,
+        reduce: """
+        function(keys, values) {
+          return sum(values);
+        }
+        """
+      },
+      huge_src_and_results: %{
+        map: """
+         function(doc) {
+           if (doc._id === "1") {
+             emit("#{String.duplicate("a", 16)}", null);
+           }
+         }
+        """,
+        reduce: """
+        function(keys, values) {
+          return "#{String.duplicate("a", 16)}";
+        }
+        """
+      },
+      lib: %{
+        baz: "exports.baz = 'bam';",
+        foo: %{
+          foo: "exports.foo = 'bar';",
+          boom: "exports.boom = 'ok';",
+          zoom: "exports.zoom = 'yeah';"
+        }
+      },
+      commonjs: %{
+        map: """
+        function(doc) {
+          emit(null, require('views/lib/foo/boom').boom);
+        }
+        """
+      }
+    },
+    shows: %{
+      simple: """
+      function() {
+        return 'ok';
+      }
+      """,
+      requirey: """
+      function() {
+        var lib = require('whatever/commonjs/upper');
+        return lib.testing;
+      }
+      """,
+      circular: """
+      function() {
+        var lib = require('whatever/commonjs/upper');
+        return JSON.stringify(this);
+      }
+      """,
+      circular_require: """
+      function() {
+        return require('whatever/commonjs/circular_one').name;
+      }
+      """,
+      idtest1: """
+      function() {
+        return require('whatever/idtest1/a/b/d');
+      }
+      """,
+      idtest2: """
+      function() {
+        return require('whatever/idtest2/a/b/d');
+      }
+      """,
+      idtest3: """
+      function() {
+        return require('whatever/idtest3/a/b');
+      }
+      """,
+      idtest4: """
+      function() {
+        return require('whatever/idtest4/a/b');
+      }
+      """,
+      idtest5: """
+      function() {
+        return require('whatever/idtest5/a');
+      }
+      """
+    }
+  }
+
+  setup_all do
+    db_name = random_db_name()
+    {:ok, _} = create_db(db_name)
+    on_exit(fn -> delete_db(db_name) end)
+
+    {:ok, _} = create_doc(db_name, @design_doc)
+    {:ok, _} = create_doc(db_name, %{})
+    {:ok, [db_name: db_name]}
+  end
+
+  test "consistent _rev for design docs", context do
+    resp = Couch.get("/#{context[:db_name]}/_design/test")
+    assert resp.status_code == 200
+    first_db_rev = resp.body["_rev"]
+
+    second_db_name = random_db_name()
+    create_db(second_db_name)
+    {:ok, resp2} = create_doc(second_db_name, @design_doc)
+    assert first_db_rev == resp2.body["rev"]
+  end
+
+  test "commonjs require", context do
+    db_name = context[:db_name]
+    resp = Couch.get("/#{db_name}/_design/test/_show/requirey")
+    assert resp.status_code == 200
+    assert resp.body == "PLANKTONwhatever/commonjs/upperplankton"
+
+    resp = Couch.get("/#{db_name}/_design/test/_show/circular")
+    assert resp.status_code == 200
+
+    result =
+      resp.body
+      |> IO.iodata_to_binary()
+      |> :jiffy.decode([:return_maps])
+
+    assert result["language"] == "javascript"
+  end
+
+  test "circular commonjs dependencies", context do
+    db_name = context[:db_name]
+    resp = Couch.get("/#{db_name}/_design/test/_show/circular_require")
+    assert resp.status_code == 200
+    assert resp.body == "One"
+  end
+
+  test "module id values are as expected", context do
+    db_name = context[:db_name]
+
+    check_id_value(db_name, "idtest1", "whatever/idtest1/a/c/e")
+    check_id_value(db_name, "idtest2", "whatever/idtest2/a/c/e")
+    check_id_value(db_name, "idtest3", "whatever/idtest3/a/c/e")
+    check_id_value(db_name, "idtest4", "whatever/idtest4/a/c/e")
+    check_id_value(db_name, "idtest5", "whatever/idtest5/b")
+  end
+
+  defp check_id_value(db_name, id, expected) do
+    resp = Couch.get("/#{db_name}/_design/test/_show/#{id}")
+    assert resp.status_code == 200
+    assert resp.body == expected
+  end
+
+  @tag :with_db
+  test "test that we get correct design doc info back", context do
+    db_name = context[:db_name]
+    {:ok, _} = create_doc(db_name, @design_doc)
+
+    resp = Couch.get("/#{db_name}/_design/test/_info")
+    prev_view_sig = resp.body["view_index"]["signature"]
+    prev_view_size = resp.body["view_index"]["sizes"]["file"]
+
+    num_docs = 500
+    bulk_save(db_name, make_docs(1..(num_docs + 1)))
+
+    Couch.get("/#{db_name}/_design/test/_view/summate", query: [stale: "ok"])
+
+    for _x <- 0..1 do
+      resp = Couch.get("/#{db_name}/_design/test/_info")
+      assert resp.body["name"] == "test"
+      assert resp.body["view_index"]["sizes"]["file"] == prev_view_size
+      assert resp.body["view_index"]["compact_running"] == false
+      assert resp.body["view_index"]["signature"] == prev_view_sig
+    end
+  end
+
+  test "commonjs in map functions", context do
+    db_name = context[:db_name]
+
+    resp = Couch.get("/#{db_name}/_design/test/_view/commonjs", query: [limit: 
1])
+    assert resp.status_code == 200
+    assert Enum.at(resp.body["rows"], 0)["value"] == "ok"
+  end
+
+  test "_all_docs view returns correctly with keys", context do
+    db_name = context[:db_name]
+
+    resp =
+      Couch.get("/#{db_name}/_all_docs",
+        query: [startkey: :jiffy.encode("_design"), endkey: 
:jiffy.encode("_design0")]
+      )
+
+    assert length(resp.body["rows"]) == 1
+  end
+
+  @tag :with_db
+  test "all_docs_twice", context do
+    db_name = context[:db_name]
+    {:ok, _} = create_doc(db_name, @design_doc)
+
+    num_docs = 500
+    bulk_save(db_name, make_docs(1..(2 * num_docs)))
+
+    for _x <- 0..1 do
+      test_all_docs_twice(db_name, num_docs)
+    end
+  end
+
+  defp test_all_docs_twice(db_name, num_docs) do
+    resp = Couch.get("/#{db_name}/_design/test/_view/all_docs_twice")
+    assert resp.status_code == 200
+    rows = resp.body["rows"]
+
+    for x <- 0..num_docs do
+      assert Map.get(Enum.at(rows, 2 * x), "key") == x + 1
+      assert Map.get(Enum.at(rows, 2 * x + 1), "key") == x + 1
+    end
+
+    resp = Couch.get("/#{db_name}/_design/test/_view/no_docs")
+    assert resp.body["total_rows"] == 0
+
+    resp = Couch.get("/#{db_name}/_design/test/_view/single_doc")
+    assert resp.body["total_rows"] == 1
+  end
+
+  @tag :with_db
+  test "language not specified, Javascript is implied", context do
+    db_name = context[:db_name]
+    bulk_save(db_name, make_docs(1..2))
+
+    design_doc_2 = %{
+      _id: "_design/test2",
+      views: %{
+        single_doc: %{
+          map: """
+          function(doc) {
+            if (doc._id === "1") {
+              emit(1, null);
+            }
+          }
+          """
+        }
+      }
+    }
+
+    {:ok, _} = create_doc(db_name, design_doc_2)
+
+    resp = Couch.get("/#{db_name}/_design/test2/_view/single_doc")
+    assert resp.status_code == 200
+    assert length(resp.body["rows"]) == 1
+  end
+
+  @tag :with_db
+  test "startkey and endkey", context do
+    db_name = context[:db_name]
+    {:ok, _} = create_doc(db_name, @design_doc)
+
+    num_docs = 500
+    bulk_save(db_name, make_docs(1..(2 * num_docs)))
+
+    resp = Couch.get("/#{db_name}/_design/test/_view/summate")
+    assert Enum.at(resp.body["rows"], 0)["value"] == summate(num_docs * 2)
+
+    resp =
+      Couch.get("/#{db_name}/_design/test/_view/summate",
+        query: [startkey: 4, endkey: 4]
+      )
+
+    assert Enum.at(resp.body["rows"], 0)["value"] == 4
+
+    resp =
+      Couch.get("/#{db_name}/_design/test/_view/summate",
+        query: [startkey: 4, endkey: 5]
+      )
+
+    assert Enum.at(resp.body["rows"], 0)["value"] == 9
+
+    resp =
+      Couch.get("/#{db_name}/_design/test/_view/summate",
+        query: [startkey: 4, endkey: 6]
+      )
+
+    assert Enum.at(resp.body["rows"], 0)["value"] == 15
+
+    # test start_key and end_key aliases
+    resp =
+      Couch.get("/#{db_name}/_design/test/_view/summate",
+        query: [start_key: 4, end_key: 6]
+      )
+
+    assert Enum.at(resp.body["rows"], 0)["value"] == 15
+
+    # Verify that a shared index (view def is an exact copy of "summate")
+    # does not confuse the reduce stage
+    resp =
+      Couch.get("/#{db_name}/_design/test/_view/summate2",
+        query: [startkey: 4, endkey: 6]
+      )
+
+    assert Enum.at(resp.body["rows"], 0)["value"] == 15
+
+    for x <- 0..Integer.floor_div(num_docs, 60) do
+      resp =
+        Couch.get("/#{db_name}/_design/test/_view/summate",
+          query: [startkey: x * 30, endkey: num_docs - x * 30]
+        )
+
+      assert Enum.at(resp.body["rows"], 0)["value"] ==
+               summate(num_docs - x * 30) - summate(x * 30 - 1)
+    end
+  end
+
+  defp summate(n) do
+    (n + 1) * (n / 2)
+  end
+
+  @tag :with_db
+  test "design doc deletion", context do
+    db_name = context[:db_name]
+    {:ok, resp} = create_doc(db_name, @design_doc)
+
+    del_resp =
+      Couch.delete("/#{db_name}/#{resp.body["id"]}", query: [rev: 
resp.body["rev"]])
+
+    assert del_resp.status_code == 200
+
+    resp = Couch.get("/#{db_name}/#{resp.body["id"]}")
+    assert resp.status_code == 404
+
+    resp = Couch.get("/#{db_name}/_design/test/_view/no_docs")
+    assert resp.status_code == 404
+  end
+
+  @tag :with_db
+  test "validate doc update", context do
+    db_name = context[:db_name]
+
+    # COUCHDB-1227 - if a design document is deleted, by adding a "_deleted"
+    # field with the boolean value true, its validate_doc_update functions
+    # should no longer have effect.
+
+    ddoc = %{
+      _id: "_design/test",
+      language: "javascript",
+      validate_doc_update: """
+        function(newDoc, oldDoc, userCtx, secObj) {
+         if (newDoc.value % 2 == 0) {
+            throw({forbidden: "dont like even numbers"});
+         }
+         return true;
+      }
+      """
+    }
+
+    {:ok, resp_ddoc} = create_doc(db_name, ddoc)
+
+    resp =
+      Couch.post("/#{db_name}",
+        body: %{_id: "doc1", value: 4}
+      )
+
+    assert resp.status_code == 403
+    assert resp.body["reason"] == "dont like even numbers"
+
+    ddoc_resp = Couch.get("/#{db_name}/#{resp_ddoc.body["id"]}")
+
+    ddoc =
+      ddoc_resp.body
+      |> Map.put("_deleted", true)
+
+    del_resp =
+      Couch.post("/#{db_name}",
+        body: ddoc
+      )
+
+    assert del_resp.status_code in [201, 202]
+
+    {:ok, _} = create_doc(db_name, %{_id: "doc1", value: 4})
+  end
+end
diff --git a/test/javascript/tests/design_docs.js 
b/test/javascript/tests/design_docs.js
index 55e592a..dd2d0e3 100644
--- a/test/javascript/tests/design_docs.js
+++ b/test/javascript/tests/design_docs.js
@@ -10,7 +10,9 @@
 // License for the specific language governing permissions and limitations 
under
 // the License.
 
+couchTests.elixir = true;
 couchTests.design_docs = function(debug) {
+  return console.log('done in test/elixir/test/design_docs.exs');
   var db_name = get_random_db_name();
   var db_name_a = get_random_db_name();
   var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"});

Reply via email to