summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorILYA Khlopotov <iilyak@apache.org>2020-05-11 08:55:08 -0700
committerILYA Khlopotov <iilyak@apache.org>2020-05-15 11:21:25 -0700
commitaf502eae5aab6282ce9509105d69acc9835d529c (patch)
tree933dc1a432eb90a5c8817bf882eb5704d9b282ad
parent404174118f9eb38d44543c6e430e938e865cc269 (diff)
downloadcouchdb-af502eae5aab6282ce9509105d69acc9835d529c.tar.gz
Add tests for legacy API before refactoring
-rw-r--r--src/chttpd/test/exunit/pagination_test.exs302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/chttpd/test/exunit/pagination_test.exs b/src/chttpd/test/exunit/pagination_test.exs
new file mode 100644
index 000000000..4b12c8b2f
--- /dev/null
+++ b/src/chttpd/test/exunit/pagination_test.exs
@@ -0,0 +1,302 @@
+defmodule Couch.Test.Pagination do
+ use ExUnit.Case
+ import Couch.DBTest, only: [retry_until: 1]
+ alias Couch.DBTest, as: Utils
+
+ defp create_admin(user_name, password) do
+ hashed = String.to_charlist(:couch_passwords.hash_admin_password(password))
+ :config.set('admins', String.to_charlist(user_name), hashed, false)
+ end
+
+ defp base_url() do
+ addr = :config.get('chttpd', 'bind_address', '127.0.0.1')
+ port = :mochiweb_socket_server.get(:chttpd, :port)
+ "http://#{addr}:#{port}"
+ end
+
+ setup_all do
+ test_ctx =
+ :test_util.start_couch([:chttpd, :couch_jobs, :couch_views, :couch_eval, :couch_js])
+
+ :ok = create_admin("adm", "pass")
+
+ on_exit(fn ->
+ :test_util.stop_couch(test_ctx)
+ end)
+
+ %{
+ base_url: base_url(),
+ user: "adm",
+ pass: "pass"
+ }
+ end
+
+ defp with_session(context) do
+ session = Couch.login(context.user, context.pass, base_url: context.base_url)
+ %{session: session}
+ end
+
+ defp random_db(context) do
+ db_name = Utils.random_db_name("db")
+
+ on_exit(fn ->
+ delete_db(context.session, db_name)
+ end)
+
+ create_db(context.session, db_name)
+ %{db_name: db_name}
+ end
+
+ defp with_docs(context) do
+ assert Map.has_key?(context, :n_docs), "Please define '@describetag n_docs: 10'"
+ %{docs: create_docs(context.session, context.db_name, 1..context.n_docs)}
+ end
+
+ defp with_view(context) do
+ ddoc_id = "simple"
+
+ ddoc = %{
+ _id: "_design/#{ddoc_id}",
+ views: %{
+ all: %{
+ map: "function(doc) { emit(doc.string, doc) }"
+ }
+ }
+ }
+
+ create_doc(context.session, context.db_name, ddoc)
+ %{view_name: "all", ddoc_id: ddoc_id}
+ end
+
+ def create_db(session, db_name, opts \\ []) do
+ retry_until(fn ->
+ resp = Couch.Session.put(session, "/#{db_name}", opts)
+ assert resp.status_code in [201, 202], "got error #{inspect(resp.body)}"
+ assert resp.body == %{"ok" => true}
+ {:ok, resp}
+ end)
+ end
+
+ defp delete_db(session, db_name) do
+ retry_until(fn ->
+ resp = Couch.Session.delete(session, "/#{db_name}")
+ assert resp.status_code in [200, 202, 404], "got error #{inspect(resp.body)}"
+ {:ok, resp}
+ end)
+ end
+
+ defp create_doc(session, db_name, body) do
+ {:ok, body} =
+ retry_until(fn ->
+ resp = Couch.Session.post(session, "/#{db_name}", body: body)
+ assert resp.status_code in [201, 202], "got error #{inspect(resp.body)}"
+ assert resp.body["ok"]
+ {:ok, resp.body}
+ end)
+
+ Map.delete(body, "ok")
+ end
+
+ defp create_docs(session, db_name, range) do
+ docs = make_docs(range)
+
+ docs
+ |> Enum.map(fn doc ->
+ create_doc(session, db_name, doc)
+ end)
+ end
+
+ defp docid(id) do
+ id |> Integer.to_string() |> String.pad_leading(3, "0")
+ end
+
+ defp make_docs(id_range) do
+ for id <- id_range do
+ str_id = docid(id)
+ %{"_id" => str_id, "integer" => id, "string" => str_id}
+ end
+ end
+
+ describe "Legacy API (10 docs)" do
+ @describetag n_docs: 10
+ setup [:with_session, :random_db, :with_docs]
+
+ test ": _all_docs/queries", ctx do
+ queries = %{
+ queries: [%{descending: false}, %{descending: true}]
+ }
+
+ resp =
+ Couch.Session.post(ctx.session, "/#{ctx.db_name}/_all_docs/queries",
+ body: :jiffy.encode(queries)
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+ [q1, q2] = resp.body["results"]
+ assert q1["rows"] == Enum.reverse(q2["rows"])
+ end
+ end
+
+ for descending <- [false, true] do
+ describe "Legacy API (10 docs) : _all_docs?descending=#{descending}" do
+ @describetag n_docs: 10
+ @describetag descending: descending
+ setup [:with_session, :random_db, :with_docs]
+
+ test "total_rows matches the length of rows array", ctx do
+ resp =
+ Couch.Session.get(ctx.session, "/#{ctx.db_name}/_all_docs",
+ query: %{descending: ctx.descending}
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+ body = resp.body
+ assert body["total_rows"] == length(body["rows"])
+ end
+
+ test "the rows are correctly sorted", ctx do
+ resp =
+ Couch.Session.get(ctx.session, "/#{ctx.db_name}/_all_docs",
+ query: %{descending: ctx.descending}
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+ body = resp.body
+ ids = Enum.map(body["rows"], fn row -> row["id"] end)
+
+ if ctx.descending do
+ assert Enum.reverse(Enum.sort(ids)) == ids
+ else
+ assert Enum.sort(ids) == ids
+ end
+ end
+
+ test "start_key is respected", ctx do
+ head_pos = 2
+ tail_pos = ctx.n_docs - head_pos
+ doc_ids = Enum.map(ctx.docs, fn doc -> doc["id"] end)
+
+ {start_pos, doc_ids} =
+ if ctx.descending do
+ {head_pos, Enum.reverse(Enum.drop(Enum.sort(doc_ids), -tail_pos))}
+ else
+ {tail_pos, Enum.drop(Enum.sort(doc_ids), tail_pos - 1)}
+ end
+
+ start_key = ~s("#{docid(start_pos)}")
+
+ resp =
+ Couch.Session.get(ctx.session, "/#{ctx.db_name}/_all_docs",
+ query: %{descending: ctx.descending, start_key: start_key}
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+ ids = Enum.map(resp.body["rows"], fn row -> row["id"] end)
+ assert doc_ids == ids
+ end
+
+ test "end_key is respected", ctx do
+ head_pos = 2
+ tail_pos = ctx.n_docs - head_pos
+ doc_ids = Enum.map(ctx.docs, fn doc -> doc["id"] end)
+
+ {end_pos, doc_ids} =
+ if ctx.descending do
+ {tail_pos, Enum.reverse(Enum.drop(Enum.sort(doc_ids), tail_pos - 1))}
+ else
+ {head_pos, Enum.drop(Enum.sort(doc_ids), -tail_pos)}
+ end
+
+ end_key = ~s("#{docid(end_pos)}")
+
+ resp =
+ Couch.Session.get(ctx.session, "/#{ctx.db_name}/_all_docs",
+ query: %{descending: ctx.descending, end_key: end_key}
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+ ids = Enum.map(resp.body["rows"], fn row -> row["id"] end)
+ assert doc_ids == ids
+ end
+
+ test "range between start_key and end_key works", ctx do
+ head_pos = 2
+ slice_size = 3
+ doc_ids = Enum.sort(Enum.map(ctx.docs, fn doc -> doc["id"] end))
+ # -1 due to 0 based indexing
+ # -2 is due to 0 based indexing and inclusive end
+ slice = Enum.slice(doc_ids, (head_pos - 1)..(head_pos + slice_size - 2))
+
+ {start_key, end_key, doc_ids} =
+ if ctx.descending do
+ reversed = Enum.reverse(slice)
+ [first | _] = reversed
+ [last | _] = slice
+ {~s("#{first}"), ~s("#{last}"), reversed}
+ else
+ [first | _] = slice
+ [last | _] = Enum.reverse(slice)
+ {~s("#{first}"), ~s("#{last}"), slice}
+ end
+
+ assert length(doc_ids) == slice_size
+
+ resp =
+ Couch.Session.get(ctx.session, "/#{ctx.db_name}/_all_docs",
+ query: %{descending: ctx.descending, start_key: start_key, end_key: end_key}
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+ ids = Enum.map(resp.body["rows"], fn row -> row["id"] end)
+ assert doc_ids == ids
+ end
+ end
+ end
+
+ describe "Legacy API (10 docs) : /{db}/_design/{ddoc}/_view" do
+ @describetag n_docs: 10
+ @describetag descending: false
+ @describetag page_size: 4
+ setup [:with_session, :random_db, :with_view, :with_docs]
+
+ test "total_rows matches the length of rows array", ctx do
+ resp =
+ Couch.Session.get(
+ ctx.session,
+ "/#{ctx.db_name}/_design/#{ctx.ddoc_id}/_view/#{ctx.view_name}",
+ query: %{descending: ctx.descending}
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+ body = resp.body
+ assert body["total_rows"] == length(body["rows"])
+ end
+ end
+
+ describe "Legacy API (10 docs) : /{db}/_design/{ddoc}/_view/queries" do
+ @describetag n_docs: 10
+ @describetag page_size: 4
+ setup [:with_session, :random_db, :with_view, :with_docs]
+
+ test "descending is respected", ctx do
+ queries = %{
+ queries: [%{descending: false}, %{descending: true}]
+ }
+
+ resp =
+ Couch.Session.post(
+ ctx.session,
+ "/#{ctx.db_name}/_design/#{ctx.ddoc_id}/_view/#{ctx.view_name}/queries",
+ body: :jiffy.encode(queries)
+ )
+
+ assert resp.status_code == 200, "got error #{inspect(resp.body)}"
+
+ [q1, q2] = resp.body["results"]
+ q1 = Enum.map(q1["rows"], fn row -> row["id"] end)
+ q2 = Enum.map(q2["rows"], fn row -> row["id"] end)
+ assert q1 == Enum.reverse(q2)
+ assert q1 == Enum.sort(q1)
+ end
+ end
+end