summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuanjo Rodriguez <jjrodrig@gmail.com>2020-03-20 00:28:06 +0100
committerGitHub <noreply@github.com>2020-03-20 00:28:06 +0100
commit4d9a35cec651c564f32234c282a44bf495a94b45 (patch)
tree4a0ae083f9529ba1ec4aa5b3e8bdc0c89ed9db9a
parent3bf47de19232ef076e843d05c626beeebd051bd7 (diff)
downloadcouchdb-4d9a35cec651c564f32234c282a44bf495a94b45.tar.gz
Port design_docs tests from js to elixir (#2641)
-rw-r--r--test/elixir/README.md2
-rw-r--r--test/elixir/test/design_docs_test.exs479
-rw-r--r--test/javascript/tests/design_docs.js2
3 files changed, 482 insertions, 1 deletions
diff --git a/test/elixir/README.md b/test/elixir/README.md
index f163dd029..3298517a3 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 000000000..258f5f72f
--- /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 55e592a18..dd2d0e307 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"});