diff options
author | Juanjo Rodriguez <jjrodrig@gmail.com> | 2020-03-04 07:39:14 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-04 07:39:14 +0100 |
commit | 0aa37dc8b8acd04542b92694e2681512dcba0fef (patch) | |
tree | 28e7f22d39c994cd741a9b10ef6f65e0a80ef461 | |
parent | e6e4c0376ea09f346e3655ce2410d66bd0cf2f20 (diff) | |
download | couchdb-0aa37dc8b8acd04542b92694e2681512dcba0fef.tar.gz |
Port changes, _design_docs, design_options and design_paths tests from js to elixir (3.0.x) (#2629)
* Port _design_docs tests, design_options and design_paths from js to elixir (#2596)
* Port changes.js test suite into elixir
-rw-r--r-- | test/elixir/README.md | 5 | ||||
-rw-r--r-- | test/elixir/test/changes_async_test.exs | 545 | ||||
-rw-r--r-- | test/elixir/test/changes_test.exs | 440 | ||||
-rw-r--r-- | test/elixir/test/design_docs_query_test.exs | 273 | ||||
-rw-r--r-- | test/elixir/test/design_docs_test.exs | 108 | ||||
-rw-r--r-- | test/elixir/test/design_options_test.exs | 74 | ||||
-rw-r--r-- | test/elixir/test/design_paths_test.exs | 76 | ||||
-rw-r--r-- | test/javascript/tests/changes.js | 7 | ||||
-rw-r--r-- | test/javascript/tests/design_docs_query.js | 2 | ||||
-rw-r--r-- | test/javascript/tests/design_options.js | 3 | ||||
-rw-r--r-- | test/javascript/tests/design_paths.js | 1 |
11 files changed, 1404 insertions, 130 deletions
diff --git a/test/elixir/README.md b/test/elixir/README.md index 5aa70bb9b..6a19c246d 100644 --- a/test/elixir/README.md +++ b/test/elixir/README.md @@ -43,8 +43,9 @@ X means done, - means partially - [X] Port cookie_auth.js - [X] Port copy_doc.js - [ ] Port design_docs.js - - [ ] Port design_options.js - - [ ] Port design_paths.js + - [X] Port design_docs_query.js + - [X] Port design_options.js + - [X] Port design_paths.js - [X] Port erlang_views.js - [X] Port etags_head.js - [ ] ~~Port etags_views.js~~ (skipped in js test suite) diff --git a/test/elixir/test/changes_async_test.exs b/test/elixir/test/changes_async_test.exs new file mode 100644 index 000000000..07afcdc7c --- /dev/null +++ b/test/elixir/test/changes_async_test.exs @@ -0,0 +1,545 @@ +defmodule ChangesAsyncTest do + use CouchTestCase + + @moduletag :changes + + @moduledoc """ + Test CouchDB /{db}/_changes + """ + + @tag :with_db + test "live changes", context do + db_name = context[:db_name] + test_changes(db_name, "live") + end + + @tag :with_db + test "continuous changes", context do + db_name = context[:db_name] + test_changes(db_name, "continuous") + end + + @tag :with_db + test "longpoll changes", context do + db_name = context[:db_name] + + check_empty_db(db_name) + + create_doc(db_name, sample_doc_foo()) + + req_id = + Couch.get("/#{db_name}/_changes?feed=longpoll", + stream_to: self() + ) + + changes = process_response(req_id.id, &parse_chunk/1) + {changes_length, last_seq_prefix} = parse_changes_response(changes) + assert changes_length == 1, "db should not be empty" + assert last_seq_prefix == "1-", "seq must start with 1-" + + last_seq = changes["last_seq"] + {:ok, worker_pid} = HTTPotion.spawn_link_worker_process(Couch.process_url("")) + + req_id = + Couch.get("/#{db_name}/_changes?feed=longpoll&since=#{last_seq}", + stream_to: self(), + direct: worker_pid + ) + + :ok = wait_for_headers(req_id.id, 200) + + create_doc_bar(db_name, "bar") + + {changes_length, last_seq_prefix} = + req_id.id + |> process_response(&parse_chunk/1) + |> parse_changes_response() + + assert changes_length == 1, "should return one change" + assert last_seq_prefix == "2-", "seq must start with 2-" + + req_id = + Couch.get("/#{db_name}/_changes?feed=longpoll&since=now", + stream_to: self(), + direct: worker_pid + ) + + :ok = wait_for_headers(req_id.id, 200) + + create_doc_bar(db_name, "barzzzz") + + changes = process_response(req_id.id, &parse_chunk/1) + {changes_length, last_seq_prefix} = parse_changes_response(changes) + assert changes_length == 1, "should return one change" + assert Enum.at(changes["results"], 0)["id"] == "barzzzz" + assert last_seq_prefix == "3-", "seq must start with 3-" + end + + @tag :with_db + test "eventsource changes", context do + db_name = context[:db_name] + + check_empty_db(db_name) + + create_doc(db_name, sample_doc_foo()) + {:ok, worker_pid} = HTTPotion.spawn_link_worker_process(Couch.process_url("")) + + req_id = + Rawresp.get("/#{db_name}/_changes?feed=eventsource&timeout=500", + stream_to: self(), + direct: worker_pid + ) + + :ok = wait_for_headers(req_id.id, 200) + + create_doc_bar(db_name, "bar") + + changes = process_response(req_id.id, &parse_event/1) + + assert length(changes) == 2 + assert Enum.at(changes, 0)["id"] == "foo" + assert Enum.at(changes, 1)["id"] == "bar" + + HTTPotion.stop_worker_process(worker_pid) + end + + @tag :with_db + test "eventsource heartbeat", context do + db_name = context[:db_name] + + {:ok, worker_pid} = HTTPotion.spawn_link_worker_process(Couch.process_url("")) + + req_id = + Rawresp.get("/#{db_name}/_changes?feed=eventsource&heartbeat=10", + stream_to: {self(), :once}, + direct: worker_pid + ) + + :ok = wait_for_headers(req_id.id, 200) + beats = wait_for_heartbeats(req_id.id, 0, 3) + assert beats == 3 + HTTPotion.stop_worker_process(worker_pid) + end + + @tag :with_db + test "longpoll filtered changes", context do + db_name = context[:db_name] + create_filters_view(db_name) + + create_doc(db_name, %{bop: "foom"}) + create_doc(db_name, %{bop: false}) + + req_id = + Couch.get("/#{db_name}/_changes?feed=longpoll&filter=changes_filter/bop", + stream_to: self() + ) + + changes = process_response(req_id.id, &parse_chunk/1) + {changes_length, last_seq_prefix} = parse_changes_response(changes) + assert changes_length == 1, "db should not be empty" + assert last_seq_prefix == "3-", "seq must start with 3-" + + last_seq = changes["last_seq"] + # longpoll waits until a matching change before returning + {:ok, worker_pid} = HTTPotion.spawn_link_worker_process(Couch.process_url("")) + + req_id = + Couch.get( + "/#{db_name}/_changes?feed=longpoll&filter=changes_filter/bop&since=#{last_seq}", + stream_to: self(), + direct: worker_pid + ) + + :ok = wait_for_headers(req_id.id, 200) + create_doc(db_name, %{_id: "falsy", bop: ""}) + # Doc doesn't match the filter + changes = process_response(req_id.id, &parse_chunk/1) + assert changes == :timeout + + # Doc matches the filter + create_doc(db_name, %{_id: "bingo", bop: "bingo"}) + changes = process_response(req_id.id, &parse_chunk/1) + {changes_length, last_seq_prefix} = parse_changes_response(changes) + assert changes_length == 1, "db should not be empty" + assert last_seq_prefix == "5-", "seq must start with 5-" + assert Enum.at(changes["results"], 0)["id"] == "bingo" + end + + @tag :with_db + test "continuous filtered changes", context do + db_name = context[:db_name] + create_filters_view(db_name) + + create_doc(db_name, %{bop: false}) + create_doc(db_name, %{_id: "bingo", bop: "bingo"}) + + {:ok, worker_pid} = HTTPotion.spawn_link_worker_process(Couch.process_url("")) + + req_id = + Rawresp.get( + "/#{db_name}/_changes?feed=continuous&filter=changes_filter/bop&timeout=500", + stream_to: self(), + direct: worker_pid + ) + + :ok = wait_for_headers(req_id.id, 200) + create_doc(db_name, %{_id: "rusty", bop: "plankton"}) + + changes = process_response(req_id.id, &parse_changes_line_chunk/1) + + changes_ids = + changes + |> Enum.filter(fn p -> Map.has_key?(p, "id") end) + |> Enum.map(fn p -> p["id"] end) + + assert Enum.member?(changes_ids, "bingo") + assert Enum.member?(changes_ids, "rusty") + assert length(changes_ids) == 2 + end + + @tag :with_db + test "continuous filtered changes with doc ids", context do + db_name = context[:db_name] + doc_ids = %{doc_ids: ["doc1", "doc3", "doc4"]} + + create_doc(db_name, %{_id: "doc1", value: 1}) + create_doc(db_name, %{_id: "doc2", value: 2}) + + {:ok, worker_pid} = HTTPotion.spawn_link_worker_process(Couch.process_url("")) + + req_id = + Rawresp.post( + "/#{db_name}/_changes?feed=continuous&timeout=500&filter=_doc_ids", + body: doc_ids, + headers: ["Content-Type": "application/json"], + stream_to: self(), + direct: worker_pid + ) + + :ok = wait_for_headers(req_id.id, 200) + create_doc(db_name, %{_id: "doc3", value: 3}) + + changes = process_response(req_id.id, &parse_changes_line_chunk/1) + + changes_ids = + changes + |> Enum.filter(fn p -> Map.has_key?(p, "id") end) + |> Enum.map(fn p -> p["id"] end) + + assert Enum.member?(changes_ids, "doc1") + assert Enum.member?(changes_ids, "doc3") + assert length(changes_ids) == 2 + end + + @tag :with_db + test "COUCHDB-1852", context do + db_name = context[:db_name] + + create_doc(db_name, %{bop: "foom"}) + create_doc(db_name, %{bop: "foom"}) + create_doc(db_name, %{bop: "foom"}) + create_doc(db_name, %{bop: "foom"}) + + resp = Couch.get("/#{db_name}/_changes") + assert length(resp.body["results"]) == 4 + seq = Enum.at(resp.body["results"], 1)["seq"] + + {:ok, worker_pid} = HTTPotion.spawn_link_worker_process(Couch.process_url("")) + + # simulate an EventSource request with a Last-Event-ID header + req_id = + Rawresp.get( + "/#{db_name}/_changes?feed=eventsource&timeout=100&since=0", + headers: [Accept: "text/event-stream", "Last-Event-ID": seq], + stream_to: self(), + direct: worker_pid + ) + + changes = process_response(req_id.id, &parse_event/1) + assert length(changes) == 2 + end + + defp wait_for_heartbeats(id, beats, expexted_beats) do + if beats < expexted_beats do + :ibrowse.stream_next(id) + is_heartbeat = process_response(id, &parse_heartbeat/1) + + case is_heartbeat do + :heartbeat -> wait_for_heartbeats(id, beats + 1, expexted_beats) + :timeout -> beats + _ -> wait_for_heartbeats(id, beats, expexted_beats) + end + else + beats + end + end + + defp wait_for_headers(id, status, timeout \\ 1000) do + receive do + %HTTPotion.AsyncHeaders{id: ^id, status_code: ^status} -> + :ok + + _ -> + wait_for_headers(id, status, timeout) + after + timeout -> :timeout + end + end + + defp process_response(id, chunk_parser, timeout \\ 1000) do + receive do + %HTTPotion.AsyncChunk{id: ^id} = msg -> + chunk_parser.(msg) + + _ -> + process_response(id, chunk_parser, timeout) + after + timeout -> :timeout + end + end + + defp parse_chunk(msg) do + msg.chunk |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps]) + end + + defp parse_event(msg) do + captures = Regex.scan(~r/data: (.*)/, msg.chunk) + + captures + |> Enum.map(fn p -> Enum.at(p, 1) end) + |> Enum.filter(fn p -> String.trim(p) != "" end) + |> Enum.map(fn p -> + p + |> IO.iodata_to_binary() + |> :jiffy.decode([:return_maps]) + end) + end + + defp parse_heartbeat(msg) do + is_heartbeat = Regex.match?(~r/event: heartbeat/, msg.chunk) + + if is_heartbeat do + :heartbeat + else + :other + end + end + + defp parse_changes_response(changes) do + {length(changes["results"]), String.slice(changes["last_seq"], 0..1)} + end + + defp check_empty_db(db_name) do + resp = Couch.get("/#{db_name}/_changes") + assert resp.body["results"] == [], "db must be empty" + assert String.at(resp.body["last_seq"], 0) == "0", "seq must start with 0" + end + + defp test_changes(db_name, feed) do + check_empty_db(db_name) + {_, resp} = create_doc(db_name, sample_doc_foo()) + rev = resp.body["rev"] + + # TODO: retry_part + resp = Couch.get("/#{db_name}/_changes") + assert length(resp.body["results"]) == 1, "db must not be empty" + assert String.at(resp.body["last_seq"], 0) == "1", "seq must start with 1" + + # increase timeout to 100 to have enough time 2 assemble + # (seems like too little timeouts kill + resp = Rawresp.get("/#{db_name}/_changes?feed=#{feed}&timeout=100") + changes = parse_changes_line(resp.body) + + change = Enum.at(changes, 0) + assert Enum.at(change["changes"], 0)["rev"] == rev + + # the sequence is not fully ordered and a complex structure now + change = Enum.at(changes, 1) + assert String.at(change["last_seq"], 0) == "1" + + # create_doc_bar(db_name,"bar") + {:ok, worker_pid} = HTTPotion.spawn_worker_process(Couch.process_url("")) + + %HTTPotion.AsyncResponse{id: req_id} = + Rawresp.get("/#{db_name}/_changes?feed=#{feed}&timeout=500", + stream_to: self(), + direct: worker_pid + ) + + :ok = wait_for_headers(req_id, 200) + create_doc_bar(db_name, "bar") + + changes = process_response(req_id, &parse_changes_line_chunk/1) + assert length(changes) == 3 + + HTTPotion.stop_worker_process(worker_pid) + end + + def create_doc_bar(db_name, id) do + create_doc(db_name, %{:_id => id, :bar => 1}) + end + + defp parse_changes_line_chunk(msg) do + parse_changes_line(msg.chunk) + end + + defp parse_changes_line(body) do + body_lines = String.split(body, "\n") + + body_lines + |> Enum.filter(fn line -> line != "" end) + |> Enum.map(fn line -> + line |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps]) + end) + end + + defp create_filters_view(db_name) do + dynamic_fun = """ + function(doc, req) { + var field = req.query.field; + return doc[field]; + } + """ + + userctx_fun = """ + function(doc, req) { + var field = req.query.field; + return doc[field]; + } + """ + + blah_fun = """ + function(doc) { + if (doc._id == "blah") { + emit(null, null); + } + } + """ + + ddoc = %{ + _id: "_design/changes_filter", + filters: %{ + bop: "function(doc, req) { return (doc.bop);}", + dynamic: dynamic_fun, + userCtx: userctx_fun, + conflicted: "function(doc, req) { return (doc._conflicts);}" + }, + options: %{ + local_seq: true + }, + views: %{ + local_seq: %{ + map: "function(doc) {emit(doc._local_seq, null)}" + }, + blah: %{ + map: blah_fun + } + } + } + + create_doc(db_name, ddoc) + end +end + +defmodule Rawresp do + use HTTPotion.Base + + @request_timeout 60_000 + @inactivity_timeout 55_000 + + def process_url("http://" <> _ = url) do + url + end + + def process_url(url) do + base_url = System.get_env("EX_COUCH_URL") || "http://127.0.0.1:15984" + base_url <> url + end + + def process_request_headers(headers, _body, options) do + headers = + headers + |> Keyword.put(:"User-Agent", "couch-potion") + + headers = + if headers[:"Content-Type"] do + headers + else + Keyword.put(headers, :"Content-Type", "application/json") + end + + case Keyword.get(options, :cookie) do + nil -> + headers + + cookie -> + Keyword.put(headers, :Cookie, cookie) + end + end + + def process_options(options) do + options + |> set_auth_options() + |> set_inactivity_timeout() + |> set_request_timeout() + end + + def process_request_body(body) do + if is_map(body) do + :jiffy.encode(body) + else + body + end + end + + def set_auth_options(options) do + if Keyword.get(options, :cookie) == nil do + headers = Keyword.get(options, :headers, []) + + if headers[:basic_auth] != nil or headers[:authorization] != nil do + options + else + username = System.get_env("EX_USERNAME") || "adm" + password = System.get_env("EX_PASSWORD") || "pass" + Keyword.put(options, :basic_auth, {username, password}) + end + else + options + end + end + + def set_inactivity_timeout(options) do + Keyword.update( + options, + :ibrowse, + [{:inactivity_timeout, @inactivity_timeout}], + fn ibrowse -> + Keyword.put_new(ibrowse, :inactivity_timeout, @inactivity_timeout) + end + ) + end + + def set_request_timeout(options) do + timeout = Application.get_env(:httpotion, :default_timeout, @request_timeout) + Keyword.put_new(options, :timeout, timeout) + end + + def login(userinfo) do + [user, pass] = String.split(userinfo, ":", parts: 2) + login(user, pass) + end + + def login(user, pass, expect \\ :success) do + resp = Couch.post("/_session", body: %{:username => user, :password => pass}) + + if expect == :success do + true = resp.body["ok"] + cookie = resp.headers[:"set-cookie"] + [token | _] = String.split(cookie, ";") + %Couch.Session{cookie: token} + else + true = Map.has_key?(resp.body, "error") + %Couch.Session{error: resp.body["error"]} + end + end +end diff --git a/test/elixir/test/changes_test.exs b/test/elixir/test/changes_test.exs index b5545087b..5bb376b9c 100644 --- a/test/elixir/test/changes_test.exs +++ b/test/elixir/test/changes_test.exs @@ -11,33 +11,441 @@ defmodule ChangesTest do test "Changes feed negative heartbeat", context do db_name = context[:db_name] - resp = Couch.get( - "/#{db_name}/_changes", - query: %{ - :feed => "continuous", - :heartbeat => -1000 - } - ) + resp = + Couch.get( + "/#{db_name}/_changes", + query: %{ + :feed => "continuous", + :heartbeat => -1000 + } + ) assert resp.status_code == 400 assert resp.body["error"] == "bad_request" - assert resp.body["reason"] == "The heartbeat value should be a positive integer (in milliseconds)." + + assert resp.body["reason"] == + "The heartbeat value should be a positive integer (in milliseconds)." end @tag :with_db test "Changes feed non-integer heartbeat", context do db_name = context[:db_name] - resp = Couch.get( - "/#{db_name}/_changes", - query: %{ - :feed => "continuous", - :heartbeat => "a1000" - } - ) + resp = + Couch.get( + "/#{db_name}/_changes", + query: %{ + :feed => "continuous", + :heartbeat => "a1000" + } + ) assert resp.status_code == 400 assert resp.body["error"] == "bad_request" - assert resp.body["reason"] == "Invalid heartbeat value. Expecting a positive integer value (in milliseconds)." + + assert resp.body["reason"] == + "Invalid heartbeat value. Expecting a positive integer value (in milliseconds)." + end + + @tag :with_db + test "function filtered changes", context do + db_name = context[:db_name] + create_filters_view(db_name) + + resp = Couch.get("/#{db_name}/_changes?filter=changes_filter/bop") + assert Enum.empty?(resp.body["results"]), "db must be empty" + + {:ok, doc_resp} = create_doc(db_name, %{bop: "foom"}) + rev = doc_resp.body["rev"] + id = doc_resp.body["id"] + create_doc(db_name, %{bop: false}) + + resp = Couch.get("/#{db_name}/_changes?filter=changes_filter/bop") + assert length(resp.body["results"]) == 1 + change_rev = get_change_rev_at(resp.body["results"], 0) + assert change_rev == rev + + doc = open_doc(db_name, id) + doc = Map.put(doc, "newattr", "a") + + doc = save_doc(db_name, doc) + + resp = Couch.get("/#{db_name}/_changes?filter=changes_filter/bop") + assert length(resp.body["results"]) == 1 + new_change_rev = get_change_rev_at(resp.body["results"], 0) + assert new_change_rev == doc["_rev"] + assert new_change_rev != change_rev + + resp = Couch.get("/#{db_name}/_changes?filter=changes_filter/dynamic&field=woox") + assert Enum.empty?(resp.body["results"]), "db must be empty" + + resp = Couch.get("/#{db_name}/_changes?filter=changes_filter/dynamic&field=bop") + assert length(resp.body["results"]) == 1, "db must have one change" + new_change_rev = get_change_rev_at(resp.body["results"], 0) + assert new_change_rev == doc["_rev"] + end + + @tag :with_db + test "non-existing desing doc for filtered changes", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_changes?filter=nothingtosee/bop") + assert resp.status_code == 404 + end + + @tag :with_db + test "non-existing function for filtered changes", context do + db_name = context[:db_name] + create_filters_view(db_name) + resp = Couch.get("/#{db_name}/_changes?filter=changes_filter/movealong") + assert resp.status_code == 404 + end + + @tag :with_db + test "non-existing desing doc and funcion for filtered changes", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_changes?filter=nothingtosee/movealong") + assert resp.status_code == 404 + end + + @tag :with_db + test "map function filtered changes", context do + db_name = context[:db_name] + create_filters_view(db_name) + create_doc(db_name, %{_id: "blah", bop: "plankton"}) + resp = Couch.get("/#{db_name}/_changes?filter=_view&view=changes_filter/blah") + assert length(resp.body["results"]) == 1 + assert Enum.at(resp.body["results"], 0)["id"] == "blah" + end + + @tag :with_db + test "changes limit", context do + db_name = context[:db_name] + + create_doc(db_name, %{_id: "blah", bop: "plankton"}) + create_doc(db_name, %{_id: "blah2", bop: "plankton"}) + create_doc(db_name, %{_id: "blah3", bop: "plankton"}) + + resp = Couch.get("/#{db_name}/_changes?limit=1") + assert length(resp.body["results"]) == 1 + + resp = Couch.get("/#{db_name}/_changes?limit=2") + assert length(resp.body["results"]) == 2 + end + + @tag :with_db + test "erlang function filtered changes", context do + db_name = context[:db_name] + create_erlang_filters_view(db_name) + + resp = Couch.get("/#{db_name}/_changes?filter=erlang/foo") + assert Enum.empty?(resp.body["results"]) + + create_doc(db_name, %{_id: "doc1", value: 1}) + create_doc(db_name, %{_id: "doc2", value: 2}) + create_doc(db_name, %{_id: "doc3", value: 3}) + create_doc(db_name, %{_id: "doc4", value: 4}) + + resp = Couch.get("/#{db_name}/_changes?filter=erlang/foo") + + changes_ids = + resp.body["results"] + |> Enum.map(fn p -> p["id"] end) + + assert Enum.member?(changes_ids, "doc2") + assert Enum.member?(changes_ids, "doc4") + assert length(resp.body["results"]) == 2 + end + + @tag :with_db + test "changes filtering on docids", context do + db_name = context[:db_name] + doc_ids = %{doc_ids: ["doc1", "doc3", "doc4"]} + + resp = + Couch.post("/#{db_name}/_changes?filter=_doc_ids", + body: doc_ids, + headers: ["Content-Type": "application/json"] + ) + + assert Enum.empty?(resp.body["results"]) + + create_doc(db_name, %{_id: "doc1", value: 1}) + create_doc(db_name, %{_id: "doc2", value: 2}) + + resp = + Couch.post("/#{db_name}/_changes?filter=_doc_ids", + body: doc_ids, + headers: ["Content-Type": "application/json"] + ) + + assert length(resp.body["results"]) == 1 + assert Enum.at(resp.body["results"], 0)["id"] == "doc1" + + create_doc(db_name, %{_id: "doc3", value: 3}) + + resp = + Couch.post("/#{db_name}/_changes?filter=_doc_ids", + body: doc_ids, + headers: ["Content-Type": "application/json"] + ) + + assert length(resp.body["results"]) == 2 + + changes_ids = + resp.body["results"] + |> Enum.map(fn p -> p["id"] end) + + assert Enum.member?(changes_ids, "doc1") + assert Enum.member?(changes_ids, "doc3") + + encoded_doc_ids = doc_ids.doc_ids |> :jiffy.encode() + + resp = + Couch.get("/#{db_name}/_changes", + query: %{filter: "_doc_ids", doc_ids: encoded_doc_ids} + ) + + assert length(resp.body["results"]) == 2 + + changes_ids = + resp.body["results"] + |> Enum.map(fn p -> p["id"] end) + + assert Enum.member?(changes_ids, "doc1") + assert Enum.member?(changes_ids, "doc3") + end + + @tag :with_db + test "changes filtering on design docs", context do + db_name = context[:db_name] + + create_erlang_filters_view(db_name) + create_doc(db_name, %{_id: "doc1", value: 1}) + + resp = Couch.get("/#{db_name}/_changes?filter=_design") + assert length(resp.body["results"]) == 1 + assert Enum.at(resp.body["results"], 0)["id"] == "_design/erlang" + end + + @tag :with_db + test "COUCHDB-1037-empty result for ?limit=1&filter=foo/bar in some cases", + context do + db_name = context[:db_name] + + filter_fun = """ + function(doc, req) { + return (typeof doc.integer === "number"); + } + """ + + ddoc = %{ + _id: "_design/testdocs", + language: "javascript", + filters: %{ + testdocsonly: filter_fun + } + } + + create_doc(db_name, ddoc) + + ddoc = %{ + _id: "_design/foobar", + foo: "bar" + } + + create_doc(db_name, ddoc) + bulk_save(db_name, make_docs(0..4)) + + resp = Couch.get("/#{db_name}/_changes") + assert length(resp.body["results"]) == 7 + + resp = Couch.get("/#{db_name}/_changes?limit=1&filter=testdocs/testdocsonly") + assert length(resp.body["results"]) == 1 + # we can't guarantee ordering + assert Regex.match?(~r/[0-4]/, Enum.at(resp.body["results"], 0)["id"]) + + resp = Couch.get("/#{db_name}/_changes?limit=2&filter=testdocs/testdocsonly") + assert length(resp.body["results"]) == 2 + # we can't guarantee ordering + assert Regex.match?(~r/[0-4]/, Enum.at(resp.body["results"], 0)["id"]) + assert Regex.match?(~r/[0-4]/, Enum.at(resp.body["results"], 1)["id"]) + end + + @tag :with_db + test "COUCHDB-1256", context do + db_name = context[:db_name] + {:ok, resp} = create_doc(db_name, %{_id: "foo", a: 123}) + create_doc(db_name, %{_id: "bar", a: 456}) + foo_rev = resp.body["rev"] + + Couch.put("/#{db_name}/foo?new_edits=false", + headers: ["Content-Type": "application/json"], + body: %{_rev: foo_rev, a: 456} + ) + + resp = Couch.get("/#{db_name}/_changes?style=all_docs") + assert length(resp.body["results"]) == 2 + + resp = + Couch.get("/#{db_name}/_changes", + query: %{style: "all_docs", since: Enum.at(resp.body["results"], 0)["seq"]} + ) + + assert length(resp.body["results"]) == 1 + end + + @tag :with_db + test "COUCHDB-1923", context do + db_name = context[:db_name] + attachment_data = "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ=" + + docs = + make_docs(20..29, %{ + _attachments: %{ + "foo.txt": %{ + content_type: "text/plain", + data: attachment_data + }, + "bar.txt": %{ + content_type: "text/plain", + data: attachment_data + } + } + }) + + bulk_save(db_name, docs) + + resp = Couch.get("/#{db_name}/_changes?include_docs=true") + assert length(resp.body["results"]) == 10 + + first_doc = Enum.at(resp.body["results"], 0)["doc"] + + assert first_doc["_attachments"]["foo.txt"]["stub"] + assert not Enum.member?(first_doc["_attachments"]["foo.txt"], "data") + assert not Enum.member?(first_doc["_attachments"]["foo.txt"], "encoding") + assert not Enum.member?(first_doc["_attachments"]["foo.txt"], "encoded_length") + assert first_doc["_attachments"]["bar.txt"]["stub"] + assert not Enum.member?(first_doc["_attachments"]["bar.txt"], "data") + assert not Enum.member?(first_doc["_attachments"]["bar.txt"], "encoding") + assert not Enum.member?(first_doc["_attachments"]["bar.txt"], "encoded_length") + + resp = Couch.get("/#{db_name}/_changes?include_docs=true&attachments=true") + assert length(resp.body["results"]) == 10 + + first_doc = Enum.at(resp.body["results"], 0)["doc"] + + assert not Enum.member?(first_doc["_attachments"]["foo.txt"], "stub") + assert first_doc["_attachments"]["foo.txt"]["data"] == attachment_data + assert not Enum.member?(first_doc["_attachments"]["foo.txt"], "encoding") + assert not Enum.member?(first_doc["_attachments"]["foo.txt"], "encoded_length") + + assert not Enum.member?(first_doc["_attachments"]["bar.txt"], "stub") + assert first_doc["_attachments"]["bar.txt"]["data"] == attachment_data + assert not Enum.member?(first_doc["_attachments"]["bar.txt"], "encoding") + assert not Enum.member?(first_doc["_attachments"]["bar.txt"], "encoded_length") + + resp = Couch.get("/#{db_name}/_changes?include_docs=true&att_encoding_info=true") + assert length(resp.body["results"]) == 10 + + first_doc = Enum.at(resp.body["results"], 0)["doc"] + + assert first_doc["_attachments"]["foo.txt"]["stub"] + assert not Enum.member?(first_doc["_attachments"]["foo.txt"], "data") + assert first_doc["_attachments"]["foo.txt"]["encoding"] == "gzip" + assert first_doc["_attachments"]["foo.txt"]["encoded_length"] == 47 + assert first_doc["_attachments"]["bar.txt"]["stub"] + assert not Enum.member?(first_doc["_attachments"]["bar.txt"], "data") + assert first_doc["_attachments"]["bar.txt"]["encoding"] == "gzip" + assert first_doc["_attachments"]["bar.txt"]["encoded_length"] == 47 + end + + defp create_erlang_filters_view(db_name) do + erlang_fun = """ + fun({Doc}, Req) -> + case couch_util:get_value(<<"value">>, Doc) of + undefined -> false; + Value -> (Value rem 2) =:= 0; + _ -> false + end + end. + """ + + ddoc = %{ + _id: "_design/erlang", + language: "erlang", + filters: %{ + foo: erlang_fun + } + } + + create_doc(db_name, ddoc) + end + + defp create_filters_view(db_name) do + dynamic_fun = """ + function(doc, req) { + var field = req.query.field; + return doc[field]; + } + """ + + userctx_fun = """ + function(doc, req) { + var field = req.query.field; + return doc[field]; + } + """ + + blah_fun = """ + function(doc) { + if (doc._id == "blah") { + emit(null, null); + } + } + """ + + ddoc = %{ + _id: "_design/changes_filter", + filters: %{ + bop: "function(doc, req) { return (doc.bop);}", + dynamic: dynamic_fun, + userCtx: userctx_fun, + conflicted: "function(doc, req) { return (doc._conflicts);}" + }, + options: %{ + local_seq: true + }, + views: %{ + local_seq: %{ + map: "function(doc) {emit(doc._local_seq, null)}" + }, + blah: %{ + map: blah_fun + } + } + } + + create_doc(db_name, ddoc) + end + + defp get_change_rev_at(results, idx) do + results + |> Enum.at(idx) + |> Map.fetch!("changes") + |> Enum.at(0) + |> Map.fetch!("rev") + end + + defp open_doc(db_name, id) do + resp = Couch.get("/#{db_name}/#{id}") + assert resp.status_code == 200 + resp.body + end + + defp save_doc(db_name, body) do + resp = Couch.put("/#{db_name}/#{body["_id"]}", body: body) + assert resp.status_code in [201, 202] + assert resp.body["ok"] + Map.put(body, "_rev", resp.body["rev"]) end end diff --git a/test/elixir/test/design_docs_query_test.exs b/test/elixir/test/design_docs_query_test.exs new file mode 100644 index 000000000..b439a2e02 --- /dev/null +++ b/test/elixir/test/design_docs_query_test.exs @@ -0,0 +1,273 @@ +defmodule DesignDocsQueryTest do + use CouchTestCase + + @moduletag :design_docs + + @moduledoc """ + Test CouchDB /{db}/_design_docs + """ + + setup_all do + db_name = random_db_name() + {:ok, _} = create_db(db_name) + on_exit(fn -> delete_db(db_name) end) + + bulk_save(db_name, make_docs(1..5)) + + Enum.each(1..5, fn x -> create_ddoc(db_name, x) end) + + {:ok, [db_name: db_name]} + end + + defp create_ddoc(db_name, idx) do + ddoc = %{ + _id: "_design/ddoc0#{idx}", + views: %{ + testing: %{ + map: "function(){emit(1,1)}" + } + } + } + + create_doc(db_name, ddoc) + end + + test "query _design_docs (GET with no parameters)", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs") + assert resp.status_code == 200, "standard get should be 200" + assert resp.body["total_rows"] == 5, "total_rows mismatch" + assert length(resp.body["rows"]) == 5, "amount of rows mismatch" + end + + test "query _design_docs with single key", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs?key=\"_design/ddoc03\"") + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 1, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 0)["key"] == "_design/ddoc03" + end + + test "query _design_docs with multiple key", context do + resp = + Couch.get( + "/#{context[:db_name]}/_design_docs", + query: %{ + :keys => "[\"_design/ddoc02\", \"_design/ddoc03\"]" + } + ) + + assert resp.status_code == 200 + assert length(Map.get(resp, :body)["rows"]) == 2 + end + + test "POST with empty body", context do + resp = + Couch.post( + "/#{context[:db_name]}/_design_docs", + body: %{} + ) + + assert resp.status_code == 200 + assert length(Map.get(resp, :body)["rows"]) == 5 + end + + test "POST with keys and limit", context do + resp = + Couch.post( + "/#{context[:db_name]}/_design_docs", + body: %{ + :keys => ["_design/ddoc02", "_design/ddoc03"], + :limit => 1 + } + ) + + assert resp.status_code == 200 + assert length(Map.get(resp, :body)["rows"]) == 1 + end + + test "POST with query parameter and JSON body", context do + resp = + Couch.post( + "/#{context[:db_name]}/_design_docs", + query: %{ + :limit => 1 + }, + body: %{ + :keys => ["_design/ddoc02", "_design/ddoc03"] + } + ) + + assert resp.status_code == 200 + assert length(Map.get(resp, :body)["rows"]) == 1 + end + + test "POST edge case with colliding parameters - query takes precedence", context do + resp = + Couch.post( + "/#{context[:db_name]}/_design_docs", + query: %{ + :limit => 0 + }, + body: %{ + :keys => ["_design/ddoc02", "_design/ddoc03"], + :limit => 2 + } + ) + + assert resp.status_code == 200 + assert Enum.empty?(Map.get(resp, :body)["rows"]) + end + + test "query _design_docs descending=true", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs?descending=true") + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 5, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 0)["key"] == "_design/ddoc05" + end + + test "query _design_docs descending=false", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs?descending=false") + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 5, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 0)["key"] == "_design/ddoc01" + end + + test "query _design_docs end_key", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs?end_key=\"_design/ddoc03\"") + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 3, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 2)["key"] == "_design/ddoc03" + end + + test "query _design_docs endkey", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs?endkey=\"_design/ddoc03\"") + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 3, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 2)["key"] == "_design/ddoc03" + end + + test "query _design_docs start_key", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs?start_key=\"_design/ddoc03\"") + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 3, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 0)["key"] == "_design/ddoc03" + end + + test "query _design_docs startkey", context do + db_name = context[:db_name] + resp = Couch.get("/#{db_name}/_design_docs?startkey=\"_design/ddoc03\"") + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 3, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 0)["key"] == "_design/ddoc03" + end + + test "query _design_docs end_key inclusive_end=true", context do + db_name = context[:db_name] + + resp = + Couch.get("/#{db_name}/_design_docs", + query: [end_key: "\"_design/ddoc03\"", inclusive_end: true] + ) + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 3, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 2)["key"] == "_design/ddoc03" + end + + test "query _design_docs end_key inclusive_end=false", context do + db_name = context[:db_name] + + resp = + Couch.get("/#{db_name}/_design_docs", + query: [end_key: "\"_design/ddoc03\"", inclusive_end: false] + ) + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 2, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 1)["key"] == "_design/ddoc02" + end + + test "query _design_docs end_key inclusive_end=false descending", context do + db_name = context[:db_name] + + resp = + Couch.get("/#{db_name}/_design_docs", + query: [end_key: "\"_design/ddoc03\"", inclusive_end: false, descending: true] + ) + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 2, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 1)["key"] == "_design/ddoc04" + end + + test "query _design_docs end_key limit", context do + db_name = context[:db_name] + + resp = + Couch.get("/#{db_name}/_design_docs", + query: [end_key: "\"_design/ddoc05\"", limit: 2] + ) + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 2, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 1)["key"] == "_design/ddoc02" + end + + test "query _design_docs end_key skip", context do + db_name = context[:db_name] + + resp = + Couch.get("/#{db_name}/_design_docs", + query: [end_key: "\"_design/ddoc05\"", skip: 2] + ) + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 3, "amount of rows mismatch" + assert Enum.at(resp.body["rows"], 0)["key"] == "_design/ddoc03" + assert Enum.at(resp.body["rows"], 2)["key"] == "_design/ddoc05" + end + + test "query _design_docs update_seq", context do + db_name = context[:db_name] + + resp = + Couch.get("/#{db_name}/_design_docs", + query: [end_key: "\"_design/ddoc05\"", update_seq: true] + ) + + assert resp.status_code == 200, "standard get should be 200" + assert Map.has_key?(resp.body, "update_seq") + end + + test "query _design_docs post with keys", context do + db_name = context[:db_name] + + resp = + Couch.post("/#{db_name}/_design_docs", + headers: ["Content-Type": "application/json"], + body: %{keys: ["_design/ddoc02", "_design/ddoc03"]} + ) + + keys = + resp.body["rows"] + |> Enum.map(fn p -> p["key"] end) + + assert resp.status_code == 200, "standard get should be 200" + assert length(resp.body["rows"]) == 2, "amount of rows mismatch" + assert Enum.member?(keys, "_design/ddoc03") + assert Enum.member?(keys, "_design/ddoc02") + end +end diff --git a/test/elixir/test/design_docs_test.exs b/test/elixir/test/design_docs_test.exs deleted file mode 100644 index ed0a0dfb5..000000000 --- a/test/elixir/test/design_docs_test.exs +++ /dev/null @@ -1,108 +0,0 @@ -defmodule DesignDocsTest do - use CouchTestCase - - @moduletag :design_docs - - @moduledoc """ - Test CouchDB /{db}/_design_docs - """ - - 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, - %{ - _id: "_design/foo", - bar: "baz" - } - ) - - {:ok, _} = create_doc( - db_name, - %{ - _id: "_design/foo2", - bar: "baz2" - } - ) - - {:ok, [db_name: db_name]} - end - - test "GET with no parameters", context do - resp = Couch.get( - "/#{context[:db_name]}/_design_docs" - ) - - assert resp.status_code == 200 - assert length(Map.get(resp, :body)["rows"]) == 2 - end - - test "GET with multiple keys", context do - resp = Couch.get( - "/#{context[:db_name]}/_design_docs", - query: %{ - :keys => "[\"_design/foo\", \"_design/foo2\"]", - } - ) - - assert resp.status_code == 200 - assert length(Map.get(resp, :body)["rows"]) == 2 - end - - test "POST with empty body", context do - resp = Couch.post( - "/#{context[:db_name]}/_design_docs", - body: %{} - ) - - assert resp.status_code == 200 - assert length(Map.get(resp, :body)["rows"]) == 2 - end - - test "POST with keys and limit", context do - resp = Couch.post( - "/#{context[:db_name]}/_design_docs", - body: %{ - :keys => ["_design/foo", "_design/foo2"], - :limit => 1 - } - ) - - assert resp.status_code == 200 - assert length(Map.get(resp, :body)["rows"]) == 1 - end - - test "POST with query parameter and JSON body", context do - resp = Couch.post( - "/#{context[:db_name]}/_design_docs", - query: %{ - :limit => 1 - }, - body: %{ - :keys => ["_design/foo", "_design/foo2"] - } - ) - - assert resp.status_code == 200 - assert length(Map.get(resp, :body)["rows"]) == 1 - end - - test "POST edge case with colliding parameters - query takes precedence", context do - resp = Couch.post( - "/#{context[:db_name]}/_design_docs", - query: %{ - :limit => 0 - }, - body: %{ - :keys => ["_design/foo", "_design/foo2"], - :limit => 2 - } - ) - - assert resp.status_code == 200 - assert Enum.empty?(Map.get(resp, :body)["rows"]) - end -end diff --git a/test/elixir/test/design_options_test.exs b/test/elixir/test/design_options_test.exs new file mode 100644 index 000000000..95a938e38 --- /dev/null +++ b/test/elixir/test/design_options_test.exs @@ -0,0 +1,74 @@ +defmodule DesignOptionsTest do + use CouchTestCase + + @moduletag :design_docs + + @moduledoc """ + Test CouchDB design documents options include_design and local_seq + """ + @tag :with_db + test "design doc options - include_desing=true", context do + db_name = context[:db_name] + + create_test_view(db_name, "_design/fu", %{include_design: true}) + + resp = Couch.get("/#{db_name}/_design/fu/_view/data") + assert resp.status_code == 200 + assert length(Map.get(resp, :body)["rows"]) == 1 + assert Enum.at(resp.body["rows"], 0)["value"] == "_design/fu" + end + + @tag :with_db + test "design doc options - include_desing=false", context do + db_name = context[:db_name] + + create_test_view(db_name, "_design/bingo", %{include_design: false}) + + resp = Couch.get("/#{db_name}/_design/bingo/_view/data") + assert resp.status_code == 200 + assert Enum.empty?(Map.get(resp, :body)["rows"]) + end + + @tag :with_db + test "design doc options - include_design default value", context do + db_name = context[:db_name] + + create_test_view(db_name, "_design/bango", %{}) + + resp = Couch.get("/#{db_name}/_design/bango/_view/data") + assert resp.status_code == 200 + assert Enum.empty?(Map.get(resp, :body)["rows"]) + end + + @tag :with_db + test "design doc options - local_seq=true", context do + db_name = context[:db_name] + + create_test_view(db_name, "_design/fu", %{include_design: true, local_seq: true}) + create_doc(db_name, %{}) + resp = Couch.get("/#{db_name}/_design/fu/_view/with_seq") + + row_with_key = + resp.body["rows"] + |> Enum.filter(fn p -> p["key"] != :null end) + + assert length(row_with_key) == 2 + end + + defp create_test_view(db_name, id, options) do + map = "function (doc) {emit(null, doc._id);}" + withseq = "function(doc) {emit(doc._local_seq, null)}" + + design_doc = %{ + _id: id, + language: "javascript", + options: options, + views: %{ + data: %{map: map}, + with_seq: %{map: withseq} + } + } + + create_doc(db_name, design_doc) + end +end diff --git a/test/elixir/test/design_paths_test.exs b/test/elixir/test/design_paths_test.exs new file mode 100644 index 000000000..b3e10c165 --- /dev/null +++ b/test/elixir/test/design_paths_test.exs @@ -0,0 +1,76 @@ +defmodule DesignPathTest do + use CouchTestCase + + @moduletag :design_docs + + @moduledoc """ + Test CouchDB design documents path + """ + @tag :with_db + test "design doc path", context do + db_name = context[:db_name] + ddoc_path_test(db_name) + end + + @tag :with_db_name + test "design doc path with slash in db name", context do + db_name = URI.encode_www_form(context[:db_name] <> "/with_slashes") + create_db(db_name) + ddoc_path_test(db_name) + end + + defp ddoc_path_test(db_name) do + create_test_view(db_name, "_design/test") + + resp = Couch.get("/#{db_name}/_design/test") + assert resp.body["_id"] == "_design/test" + + resp = + Couch.get(Couch.process_url("/#{db_name}/_design%2Ftest"), + follow_redirects: true + ) + + assert resp.body["_id"] == "_design/test" + + resp = Couch.get("/#{db_name}/_design/test/_view/testing") + assert Enum.empty?(Map.get(resp, :body)["rows"]) + + design_doc2 = %{ + _id: "_design/test2", + views: %{ + testing: %{ + map: "function(){emit(1,1)}" + } + } + } + + resp = Couch.put("/#{db_name}/_design/test2", body: design_doc2) + assert resp.status_code == 201 + + resp = Couch.get("/#{db_name}/_design/test2") + assert resp.body["_id"] == "_design/test2" + + resp = + Couch.get(Couch.process_url("/#{db_name}/_design%2Ftest2"), + follow_redirects: true + ) + + assert resp.body["_id"] == "_design/test2" + + resp = Couch.get("/#{db_name}/_design/test2/_view/testing") + assert Enum.empty?(Map.get(resp, :body)["rows"]) + end + + defp create_test_view(db_name, id) do + design_doc = %{ + _id: id, + views: %{ + testing: %{ + map: "function(){emit(1,1)}" + } + } + } + + create_doc(db_name, design_doc) + end +end diff --git a/test/javascript/tests/changes.js b/test/javascript/tests/changes.js index d312edc41..d98e37cc8 100644 --- a/test/javascript/tests/changes.js +++ b/test/javascript/tests/changes.js @@ -11,6 +11,7 @@ // the License. function jsonp(obj) { + return console.log('done in test/elixir/test/changes_test.exs and changes_async_test.exs'); T(jsonp_flag == 0); T(obj.results.length == 1 && obj.last_seq == 1, "jsonp"); jsonp_flag = 1; @@ -359,7 +360,7 @@ couchTests.changes = function(debug) { resp = JSON.parse(req.responseText); T(resp.results.length == 1, "changes_filter/dynamic&field=bop"); T(resp.results[0].changes[0].rev == docres1.rev, "filtered/dynamic&field=bop rev"); - + // these will NEVER run as we're always in navigator == undefined if (!is_safari && xhr) { // full test requires parallel connections // filter with longpoll @@ -708,7 +709,7 @@ couchTests.changes = function(debug) { db = new CouchDB(db_name, {"X-Couch-Full-Commit":"true"}, {"w": 3}); T(db.createDb()); - // create 4 documents... this assumes the update sequnce will start from 0 and then do sth in the cluster + // create 4 documents... this assumes the update sequnce will start from 0 and then do sth in the cluster db.save({"bop" : "foom"}); db.save({"bop" : "foom"}); db.save({"bop" : "foom"}); @@ -717,7 +718,7 @@ couchTests.changes = function(debug) { req = CouchDB.request("GET", "/" + db_name + "/_changes"); // simulate an EventSource request with a Last-Event-ID header - // increase timeout to 100 to have enough time 2 assemble (seems like too little timeouts kill + // increase timeout to 100 to have enough time 2 assemble (seems like too little timeouts kill req = CouchDB.request("GET", "/" + db_name + "/_changes?feed=eventsource&timeout=100&since=0", {"headers": {"Accept": "text/event-stream", "Last-Event-ID": JSON.parse(req.responseText).results[1].seq}}); diff --git a/test/javascript/tests/design_docs_query.js b/test/javascript/tests/design_docs_query.js index 07e6577ab..2aefe49b4 100644 --- a/test/javascript/tests/design_docs_query.js +++ b/test/javascript/tests/design_docs_query.js @@ -11,6 +11,8 @@ // the License. couchTests.design_docs_query = function(debug) { + return console.log('done in test/elixir/test/design_docs_query_test.exs'); + var db_name = get_random_db_name(); var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"}); db.createDb(); diff --git a/test/javascript/tests/design_options.js b/test/javascript/tests/design_options.js index cc2571f6b..d3f8594d4 100644 --- a/test/javascript/tests/design_options.js +++ b/test/javascript/tests/design_options.js @@ -11,6 +11,7 @@ // the License. couchTests.design_options = function(debug) { + return console.log('done in test/elixir/test/design_options.exs'); var db_name = get_random_db_name(); var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"}); db.createDb(); @@ -36,7 +37,7 @@ couchTests.design_options = function(debug) { T(db.save(designDoc).ok); // should work for temp views - // no more there on cluster - pointless test + // no more there on cluster - pointless test //var rows = db.query(map, null, {options:{include_design: true}}).rows; //T(rows.length == 1); //T(rows[0].value == "_design/fu"); diff --git a/test/javascript/tests/design_paths.js b/test/javascript/tests/design_paths.js index 6e816991a..b85426acf 100644 --- a/test/javascript/tests/design_paths.js +++ b/test/javascript/tests/design_paths.js @@ -11,6 +11,7 @@ // the License. couchTests.design_paths = function(debug) { + return console.log('done in test/elixir/test/design_paths.exs'); if (debug) debugger; var db_name = get_random_db_name() var dbNames = [db_name, db_name + "/with_slashes"]; |