summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Mironov <ivan.mironov@gmail.com>2018-12-07 16:47:21 -0500
committerJoan Touzet <wohali@users.noreply.github.com>2018-12-07 16:47:21 -0500
commit77eb982bd9cd078e45e4a424e7ffa46f7073bfa5 (patch)
tree8d4e398d3cc5b246fe3dd9c37f56de5d7463f4a1
parentf9354ea21d2f5161e0403fbded404506405a5d70 (diff)
downloadcouchdb-77eb982bd9cd078e45e4a424e7ffa46f7073bfa5.tar.gz
Refactor elixir test suite initialization (#1779)
* Move CouchTestCase to separate file * Move setup context functions to separate module
-rw-r--r--test/elixir/lib/couch/db_test.ex240
-rw-r--r--test/elixir/mix.exs5
-rw-r--r--test/elixir/test/support/couch_test_case.ex27
-rw-r--r--test/elixir/test/test_helper.exs262
4 files changed, 272 insertions, 262 deletions
diff --git a/test/elixir/lib/couch/db_test.ex b/test/elixir/lib/couch/db_test.ex
new file mode 100644
index 000000000..538a99877
--- /dev/null
+++ b/test/elixir/lib/couch/db_test.ex
@@ -0,0 +1,240 @@
+defmodule Couch.DBTest do
+ import ExUnit.Callbacks, only: [on_exit: 1]
+ import ExUnit.Assertions, only: [assert: 1, assert: 2]
+
+ def set_db_context(context) do
+ context =
+ case context do
+ %{:with_db_name => true} ->
+ Map.put(context, :db_name, random_db_name())
+
+ %{:with_db_name => db_name} when is_binary(db_name) ->
+ Map.put(context, :db_name, db_name)
+
+ %{:with_random_db => db_name} when is_binary(db_name) ->
+ context
+ |> Map.put(:db_name, random_db_name(db_name))
+ |> Map.put(:with_db, true)
+
+ %{:with_db => true} ->
+ Map.put(context, :db_name, random_db_name())
+
+ %{:with_db => db_name} when is_binary(db_name) ->
+ Map.put(context, :db_name, db_name)
+
+ _ ->
+ context
+ end
+
+ if Map.has_key?(context, :with_db) do
+ {:ok, _} = create_db(context[:db_name])
+ on_exit(fn -> delete_db(context[:db_name]) end)
+ end
+
+ context
+ end
+
+ def set_config_context(context) do
+ if is_list(context[:config]) do
+ Enum.each(context[:config], fn cfg ->
+ set_config(cfg)
+ end)
+ end
+
+ context
+ end
+
+ def set_user_context(context) do
+ case Map.get(context, :user) do
+ nil ->
+ context
+
+ user when is_list(user) ->
+ user = create_user(user)
+
+ on_exit(fn ->
+ query = %{:rev => user["_rev"]}
+ resp = Couch.delete("/_users/#{user["_id"]}", query: query)
+ assert HTTPotion.Response.success?(resp)
+ end)
+
+ context = Map.put(context, :user, user)
+ userinfo = user["name"] <> ":" <> user["password"]
+ Map.put(context, :userinfo, userinfo)
+ end
+ end
+
+ def random_db_name do
+ random_db_name("random-test-db")
+ end
+
+ def random_db_name(prefix) do
+ time = :erlang.monotonic_time()
+ umi = :erlang.unique_integer([:monotonic])
+ "#{prefix}-#{time}-#{umi}"
+ end
+
+ def set_config({section, key, value}) do
+ existing = set_config_raw(section, key, value)
+
+ on_exit(fn ->
+ Enum.each(existing, fn {node, prev_value} ->
+ if prev_value != "" do
+ url = "/_node/#{node}/_config/#{section}/#{key}"
+ headers = ["X-Couch-Persist": "false"]
+ body = :jiffy.encode(prev_value)
+ resp = Couch.put(url, headers: headers, body: body)
+ assert resp.status_code == 200
+ else
+ url = "/_node/#{node}/_config/#{section}/#{key}"
+ headers = ["X-Couch-Persist": "false"]
+ resp = Couch.delete(url, headers: headers)
+ assert resp.status_code == 200
+ end
+ end)
+ end)
+ end
+
+ def set_config_raw(section, key, value) do
+ resp = Couch.get("/_membership")
+
+ Enum.map(resp.body["all_nodes"], fn node ->
+ url = "/_node/#{node}/_config/#{section}/#{key}"
+ headers = ["X-Couch-Persist": "false"]
+ body = :jiffy.encode(value)
+ resp = Couch.put(url, headers: headers, body: body)
+ assert resp.status_code == 200
+ {node, resp.body}
+ end)
+ end
+
+ def create_user(user) do
+ required = [:name, :password, :roles]
+
+ Enum.each(required, fn key ->
+ assert Keyword.has_key?(user, key), "User missing key: #{key}"
+ end)
+
+ name = Keyword.get(user, :name)
+ password = Keyword.get(user, :password)
+ roles = Keyword.get(user, :roles)
+
+ assert is_binary(name), "User name must be a string"
+ assert is_binary(password), "User password must be a string"
+ assert is_list(roles), "Roles must be a list of strings"
+
+ Enum.each(roles, fn role ->
+ assert is_binary(role), "Roles must be a list of strings"
+ end)
+
+ user_doc = %{
+ "_id" => "org.couchdb.user:" <> name,
+ "type" => "user",
+ "name" => name,
+ "roles" => roles,
+ "password" => password
+ }
+
+ resp = Couch.get("/_users/#{user_doc["_id"]}")
+
+ user_doc =
+ case resp.status_code do
+ 404 ->
+ user_doc
+
+ sc when sc >= 200 and sc < 300 ->
+ Map.put(user_doc, "_rev", resp.body["_rev"])
+ end
+
+ resp = Couch.post("/_users", body: user_doc)
+ assert HTTPotion.Response.success?(resp)
+ assert resp.body["ok"]
+ Map.put(user_doc, "_rev", resp.body["rev"])
+ end
+
+ def create_db(db_name) do
+ resp = Couch.put("/#{db_name}")
+ assert resp.status_code == 201
+ assert resp.body == %{"ok" => true}
+ {:ok, resp}
+ end
+
+ def delete_db(db_name) do
+ resp = Couch.delete("/#{db_name}")
+ assert resp.status_code == 200
+ assert resp.body == %{"ok" => true}
+ {:ok, resp}
+ end
+
+ def create_doc(db_name, body) do
+ resp = Couch.post("/#{db_name}", body: body)
+ assert resp.status_code == 201
+ assert resp.body["ok"]
+ {:ok, resp}
+ end
+
+ def sample_doc_foo do
+ %{
+ _id: "foo",
+ bar: "baz"
+ }
+ end
+
+ # Generate range of docs with strings as keys
+ def make_docs(id_range) do
+ for id <- id_range, str_id = Integer.to_string(id) do
+ %{"_id" => str_id, "integer" => id, "string" => str_id}
+ end
+ end
+
+ # Generate range of docs with atoms as keys, which are more
+ # idiomatic, and are encoded by jiffy to binaries
+ def create_docs(id_range) do
+ for id <- id_range, str_id = Integer.to_string(id) do
+ %{_id: str_id, integer: id, string: str_id}
+ end
+ end
+
+ def retry_until(condition, sleep \\ 100, timeout \\ 5000) do
+ retry_until(condition, now(:ms), sleep, timeout)
+ end
+
+ defp retry_until(condition, start, sleep, timeout) do
+ now = now(:ms)
+
+ if now > start + timeout do
+ raise "timed out after #{now - start} ms"
+ else
+ try do
+ if condition.() do
+ :ok
+ else
+ raise ExUnit.AssertionError
+ end
+ rescue
+ ExUnit.AssertionError ->
+ :timer.sleep(sleep)
+ retry_until(condition, start, sleep, timeout)
+ end
+ end
+ end
+
+ defp now(:ms) do
+ div(:erlang.system_time(), 1_000_000)
+ end
+
+ @spec rev(map(), map()) :: map()
+ def rev(doc = %{_id: id}, %{"id" => id, "rev" => rev}) do
+ Map.put(doc, :_rev, rev)
+ end
+
+ @spec rev([map()], [map()]) :: [map()]
+ def rev(docs, rows) when length(docs) == length(rows) do
+ for {doc, row} <- Enum.zip(docs, rows), do: rev(doc, row)
+ end
+
+ def pretty_inspect(resp) do
+ opts = [pretty: true, width: 20, limit: :infinity, printable_limit: :infinity]
+ inspect(resp, opts)
+ end
+end
diff --git a/test/elixir/mix.exs b/test/elixir/mix.exs
index 86f4c7aa0..68de5ce7a 100644
--- a/test/elixir/mix.exs
+++ b/test/elixir/mix.exs
@@ -6,6 +6,7 @@ defmodule Foo.Mixfile do
app: :foo,
version: "0.1.0",
elixir: "~> 1.5",
+ elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
deps: deps()
]
@@ -18,6 +19,10 @@ defmodule Foo.Mixfile do
]
end
+ # Specifies which paths to compile per environment.
+ defp elixirc_paths(:test), do: ["lib", "test/support"]
+ defp elixirc_paths(_), do: ["lib"]
+
# Run "mix help deps" to learn about dependencies.
defp deps do
[
diff --git a/test/elixir/test/support/couch_test_case.ex b/test/elixir/test/support/couch_test_case.ex
new file mode 100644
index 000000000..02bee46af
--- /dev/null
+++ b/test/elixir/test/support/couch_test_case.ex
@@ -0,0 +1,27 @@
+defmodule CouchTestCase do
+ use ExUnit.CaseTemplate
+
+ using do
+ quote do
+ require Logger
+ use ExUnit.Case
+
+ import Couch.DBTest
+ end
+ end
+
+ setup context do
+ setup_funs = [
+ &Couch.DBTest.set_db_context/1,
+ &Couch.DBTest.set_config_context/1,
+ &Couch.DBTest.set_user_context/1
+ ]
+
+ context =
+ Enum.reduce(setup_funs, context, fn setup_fun, acc ->
+ setup_fun.(acc)
+ end)
+
+ {:ok, context}
+ end
+end
diff --git a/test/elixir/test/test_helper.exs b/test/elixir/test/test_helper.exs
index e08229f82..33041fd02 100644
--- a/test/elixir/test/test_helper.exs
+++ b/test/elixir/test/test_helper.exs
@@ -1,264 +1,2 @@
ExUnit.configure(exclude: [pending: true])
ExUnit.start()
-
-defmodule CouchTestCase do
- use ExUnit.Case
-
- defmacro __using__(_opts) do
- quote do
- require Logger
- use ExUnit.Case
-
- setup context do
- setup_funs = [
- &set_db_context/1,
- &set_config_context/1,
- &set_user_context/1
- ]
-
- context =
- Enum.reduce(setup_funs, context, fn setup_fun, acc ->
- setup_fun.(acc)
- end)
-
- {:ok, context}
- end
-
- def set_db_context(context) do
- context =
- case context do
- %{:with_db_name => true} ->
- Map.put(context, :db_name, random_db_name())
-
- %{:with_db_name => db_name} when is_binary(db_name) ->
- Map.put(context, :db_name, db_name)
-
- %{:with_random_db => db_name} when is_binary(db_name) ->
- context
- |> Map.put(:db_name, random_db_name(db_name))
- |> Map.put(:with_db, true)
-
- %{:with_db => true} ->
- Map.put(context, :db_name, random_db_name())
-
- %{:with_db => db_name} when is_binary(db_name) ->
- Map.put(context, :db_name, db_name)
-
- _ ->
- context
- end
-
- if Map.has_key?(context, :with_db) do
- {:ok, _} = create_db(context[:db_name])
- on_exit(fn -> delete_db(context[:db_name]) end)
- end
-
- context
- end
-
- def set_config_context(context) do
- if is_list(context[:config]) do
- Enum.each(context[:config], fn cfg ->
- set_config(cfg)
- end)
- end
-
- context
- end
-
- def set_user_context(context) do
- case Map.get(context, :user) do
- nil ->
- context
-
- user when is_list(user) ->
- user = create_user(user)
-
- on_exit(fn ->
- query = %{:rev => user["_rev"]}
- resp = Couch.delete("/_users/#{user["_id"]}", query: query)
- assert HTTPotion.Response.success?(resp)
- end)
-
- context = Map.put(context, :user, user)
- userinfo = user["name"] <> ":" <> user["password"]
- Map.put(context, :userinfo, userinfo)
- end
- end
-
- def random_db_name do
- random_db_name("random-test-db")
- end
-
- def random_db_name(prefix) do
- time = :erlang.monotonic_time()
- umi = :erlang.unique_integer([:monotonic])
- "#{prefix}-#{time}-#{umi}"
- end
-
- def set_config({section, key, value}) do
- existing = set_config_raw(section, key, value)
-
- on_exit(fn ->
- Enum.each(existing, fn {node, prev_value} ->
- if prev_value != "" do
- url = "/_node/#{node}/_config/#{section}/#{key}"
- headers = ["X-Couch-Persist": "false"]
- body = :jiffy.encode(prev_value)
- resp = Couch.put(url, headers: headers, body: body)
- assert resp.status_code == 200
- else
- url = "/_node/#{node}/_config/#{section}/#{key}"
- headers = ["X-Couch-Persist": "false"]
- resp = Couch.delete(url, headers: headers)
- assert resp.status_code == 200
- end
- end)
- end)
- end
-
- def set_config_raw(section, key, value) do
- resp = Couch.get("/_membership")
-
- Enum.map(resp.body["all_nodes"], fn node ->
- url = "/_node/#{node}/_config/#{section}/#{key}"
- headers = ["X-Couch-Persist": "false"]
- body = :jiffy.encode(value)
- resp = Couch.put(url, headers: headers, body: body)
- assert resp.status_code == 200
- {node, resp.body}
- end)
- end
-
- def create_user(user) do
- required = [:name, :password, :roles]
-
- Enum.each(required, fn key ->
- assert Keyword.has_key?(user, key), "User missing key: #{key}"
- end)
-
- name = Keyword.get(user, :name)
- password = Keyword.get(user, :password)
- roles = Keyword.get(user, :roles)
-
- assert is_binary(name), "User name must be a string"
- assert is_binary(password), "User password must be a string"
- assert is_list(roles), "Roles must be a list of strings"
-
- Enum.each(roles, fn role ->
- assert is_binary(role), "Roles must be a list of strings"
- end)
-
- user_doc = %{
- "_id" => "org.couchdb.user:" <> name,
- "type" => "user",
- "name" => name,
- "roles" => roles,
- "password" => password
- }
-
- resp = Couch.get("/_users/#{user_doc["_id"]}")
-
- user_doc =
- case resp.status_code do
- 404 ->
- user_doc
-
- sc when sc >= 200 and sc < 300 ->
- Map.put(user_doc, "_rev", resp.body["_rev"])
- end
-
- resp = Couch.post("/_users", body: user_doc)
- assert HTTPotion.Response.success?(resp)
- assert resp.body["ok"]
- Map.put(user_doc, "_rev", resp.body["rev"])
- end
-
- def create_db(db_name) do
- resp = Couch.put("/#{db_name}")
- assert resp.status_code == 201
- assert resp.body == %{"ok" => true}
- {:ok, resp}
- end
-
- def delete_db(db_name) do
- resp = Couch.delete("/#{db_name}")
- assert resp.status_code == 200
- assert resp.body == %{"ok" => true}
- {:ok, resp}
- end
-
- def create_doc(db_name, body) do
- resp = Couch.post("/#{db_name}", body: body)
- assert resp.status_code == 201
- assert resp.body["ok"]
- {:ok, resp}
- end
-
- def sample_doc_foo do
- %{
- _id: "foo",
- bar: "baz"
- }
- end
-
- # Generate range of docs with strings as keys
- def make_docs(id_range) do
- for id <- id_range, str_id = Integer.to_string(id) do
- %{"_id" => str_id, "integer" => id, "string" => str_id}
- end
- end
-
- # Generate range of docs with atoms as keys, which are more
- # idiomatic, and are encoded by jiffy to binaries
- def create_docs(id_range) do
- for id <- id_range, str_id = Integer.to_string(id) do
- %{_id: str_id, integer: id, string: str_id}
- end
- end
-
- def retry_until(condition, sleep \\ 100, timeout \\ 5000) do
- retry_until(condition, now(:ms), sleep, timeout)
- end
-
- defp retry_until(condition, start, sleep, timeout) do
- now = now(:ms)
-
- if now > start + timeout do
- raise "timed out after #{now - start} ms"
- else
- try do
- if condition.() do
- :ok
- else
- raise ExUnit.AssertionError
- end
- rescue
- ExUnit.AssertionError ->
- :timer.sleep(sleep)
- retry_until(condition, start, sleep, timeout)
- end
- end
- end
-
- defp now(:ms) do
- div(:erlang.system_time(), 1_000_000)
- end
-
- @spec rev(map(), map()) :: map()
- def rev(doc = %{_id: id}, %{"id" => id, "rev" => rev}) do
- Map.put(doc, :_rev, rev)
- end
-
- @spec rev([map()], [map()]) :: [map()]
- def rev(docs, rows) when length(docs) == length(rows) do
- for {doc, row} <- Enum.zip(docs, rows), do: rev(doc, row)
- end
-
- def pretty_inspect(resp) do
- opts = [pretty: true, width: 20, limit: :infinity, printable_limit: :infinity]
- inspect(resp, opts)
- end
- end
- end
-end