diff options
author | Juanjo Rodriguez <jjrodrig@gmail.com> | 2019-04-11 23:52:51 +0200 |
---|---|---|
committer | Juanjo Rodriguez <jjrodrig@gmail.com> | 2019-04-11 23:52:51 +0200 |
commit | 0709ccf95cfd39076baee6d87035a79a56d556b1 (patch) | |
tree | 4e6fa5b1e10622627fa34c4c618fbeddf9396376 | |
parent | 5d199268d4330b80ce54d5dad2fe27db4bb81641 (diff) | |
download | couchdb-0709ccf95cfd39076baee6d87035a79a56d556b1.tar.gz |
Add auth cache test into elixir test suite
-rw-r--r-- | test/elixir/lib/couch.ex | 19 | ||||
-rw-r--r-- | test/elixir/lib/couch/db_test.ex | 56 | ||||
-rw-r--r-- | test/elixir/test/auth_cache_test.exs | 195 |
3 files changed, 259 insertions, 11 deletions
diff --git a/test/elixir/lib/couch.ex b/test/elixir/lib/couch.ex index 58581b2fd..795405b51 100644 --- a/test/elixir/lib/couch.ex +++ b/test/elixir/lib/couch.ex @@ -3,11 +3,10 @@ defmodule Couch.Session do CouchDB session helpers. """ - @enforce_keys [:cookie] - defstruct [:cookie] + defstruct [:cookie, :error] - def new(cookie) do - %Couch.Session{cookie: cookie} + def new(cookie, error \\ "") do + %Couch.Session{cookie: cookie, error: error} end def logout(sess) do @@ -119,10 +118,14 @@ defmodule Couch do def login(user, pass) do resp = Couch.post("/_session", body: %{:username => user, :password => pass}) - true = resp.body["ok"] - cookie = resp.headers[:"set-cookie"] - [token | _] = String.split(cookie, ";") - %Couch.Session{cookie: token} + + if resp.body["ok"] do + cookie = resp.headers[:"set-cookie"] + [token | _] = String.split(cookie, ";") + %Couch.Session{cookie: token} + else + %Couch.Session{error: resp.body["error"]} + end end # HACK: this is here until this commit lands in a release diff --git a/test/elixir/lib/couch/db_test.ex b/test/elixir/lib/couch/db_test.ex index 990173a13..0b5f03c70 100644 --- a/test/elixir/lib/couch/db_test.ex +++ b/test/elixir/lib/couch/db_test.ex @@ -116,13 +116,14 @@ defmodule Couch.DBTest do end) end - def create_user(user) do + def prepare_user_doc(user) do required = [:name, :password, :roles] Enum.each(required, fn key -> assert Keyword.has_key?(user, key), "User missing key: #{key}" end) + id = Keyword.get(user, :id) name = Keyword.get(user, :name) password = Keyword.get(user, :password) roles = Keyword.get(user, :roles) @@ -135,14 +136,17 @@ defmodule Couch.DBTest do assert is_binary(role), "Roles must be a list of strings" end) - user_doc = %{ - "_id" => "org.couchdb.user:" <> name, + %{ + "_id" => id || "org.couchdb.user:" <> name, "type" => "user", "name" => name, "roles" => roles, "password" => password } + end + def create_user(user) do + user_doc = prepare_user_doc(user) resp = Couch.get("/_users/#{user_doc["_id"]}") user_doc = @@ -182,6 +186,32 @@ defmodule Couch.DBTest do {:ok, resp} end + def 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"] + {:ok, resp} + end + + def delete_doc(db_name, body) do + resp = Couch.delete("/#{db_name}/#{body["_id"]}", query: [rev: body["_rev"]]) + assert resp.status_code in [200, 202] + assert resp.body["ok"] + {:ok, resp} + end + + def compact(db_name) do + resp = Couch.post("/#{db_name}/_compact") + assert resp.status_code == 202 + resp.body + end + + def info(db_name) do + resp = Couch.get("/#{db_name}") + assert resp.status_code == 200 + resp.body + end + def bulk_save(db_name, docs) do resp = Couch.post( @@ -290,6 +320,26 @@ defmodule Couch.DBTest do end end + def request_stats(path_steps, is_test) do + path = + List.foldl( + path_steps, + "/_node/_local/_stats", + fn p, acc -> + "#{acc}/#{p}" + end + ) + + path = + if is_test do + path <> "?flush=true" + else + path + end + + Couch.get(path).body + end + def retry_until(condition, sleep \\ 100, timeout \\ 5000) do retry_until(condition, now(:ms), sleep, timeout) end diff --git a/test/elixir/test/auth_cache_test.exs b/test/elixir/test/auth_cache_test.exs new file mode 100644 index 000000000..8baa1e094 --- /dev/null +++ b/test/elixir/test/auth_cache_test.exs @@ -0,0 +1,195 @@ +defmodule AuthCacheTest do + use CouchTestCase + + @moduletag :authentication + @tag :with_db + test "test auth cache management", context do + db_name = context[:db_name] + + server_config = [ + %{ + :section => "chttpd_auth", + :key => "authentication_db", + :value => db_name + }, + %{ + :section => "chttpd_auth", + :key => "auth_cache_size", + :value => "3" + }, + %{ + :section => "httpd", + :key => "authentication_handlers", + :value => "{couch_httpd_auth, default_authentication_handler}" + }, + %{ + :section => "chttpd_auth", + :key => "secret", + :value => generate_secret(64) + } + ] + + run_on_modified_server(server_config, fn -> test_fun(db_name) end) + end + + defp generate_secret(length) do + tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + + for _i <- 1..length, into: "" do + String.at(tab, trunc(Float.floor(:rand.uniform() * 64))) + end + end + + defp hits() do + hits = request_stats(["couchdb", "auth_cache_hits"], true) + hits["value"] || 0 + end + + defp misses() do + misses = request_stats(["couchdb", "auth_cache_misses"], true) + misses["value"] || 0 + end + + defp logout(session) do + assert Couch.Session.logout(session).body["ok"] + end + + defp login_fail(user, password) do + resp = Couch.login(user, password) + assert resp.error, "Login error is expected." + end + + defp login(user, password) do + sess = Couch.login(user, password) + assert sess.cookie, "Login correct is expected" + sess + end + + defp wait_until_compact_complete(db_name) do + info = info(db_name) + + if info["compact_running"] do + wait_until_compact_complete(db_name) + end + end + + defp assert_cache(event, user, password, expect \\ :expect_login_success) do + hits_before = hits() + misses_before = misses() + + session = + case expect do + :expect_login_success -> login(user, password) + :expect_login_fail -> login_fail(user, password) + _ -> assert false + end + + hits_after = hits() + misses_after = misses() + + if expect == :expect_success do + logout(session) + end + + case event do + :expect_miss -> + assert misses_after == misses_before + 1, + "Cache miss is expected for #{user} after login" + + assert hits_after == hits_before, + "No cache hit is expected for #{user} after login" + + :expect_hit -> + assert misses_after == misses_before, + "No cache miss is expected for #{user} after login" + + assert hits_after == hits_before + 1, + "Cache hit is expected for #{user} after login" + + _ -> + assert false + end + end + + defp test_fun(db_name) do + fdmanana = + prepare_user_doc([ + {:name, "fdmanana"}, + {:password, "qwerty"}, + {:roles, ["dev"]} + ]) + + {:ok, resp} = create_doc(db_name, fdmanana) + fdmanana = Map.put(fdmanana, "_rev", resp.body["rev"]) + + chris = + prepare_user_doc([ + {:name, "chris"}, + {:password, "the_god_father"}, + {:roles, ["dev", "mafia", "white_costume"]} + ]) + + create_doc(db_name, chris) + + joe = + prepare_user_doc([ + {:name, "joe"}, + {:password, "functional"}, + {:roles, ["erlnager"]} + ]) + + create_doc(db_name, joe) + + johndoe = + prepare_user_doc([ + {:name, "johndoe"}, + {:password, "123456"}, + {:roles, ["user"]} + ]) + + create_doc(db_name, johndoe) + + assert_cache(:expect_miss, "fdmanana", "qwerty") + assert_cache(:expect_hit, "fdmanana", "qwerty") + assert_cache(:expect_miss, "chris", "the_god_father") + assert_cache(:expect_miss, "joe", "functional") + assert_cache(:expect_miss, "johndoe", "123456") + + # It's a MRU cache, joe was removed from cache to add johndoe + # BUGGED assert_cache(:expect_miss, "joe", "functional") + + assert_cache(:expect_hit, "fdmanana", "qwerty") + + fdmanana = Map.replace!(fdmanana, "password", "foobar") + {:ok, resp} = save_doc(db_name, fdmanana) + second_rev = resp.body["rev"] + + # Cache was refreshed + # BUGGED + # assert_cache(:expect_hit, "fdmanana", "qwerty", :expect_login_fail) + # assert_cache(:expect_hit, "fdmanana", "foobar") + + # and yet another update + fdmanana = Map.replace!(fdmanana, "password", "javascript") + fdmanana = Map.replace!(fdmanana, "_rev", second_rev) + {:ok, resp} = save_doc(db_name, fdmanana) + third_rev = resp.body["rev"] + fdmanana = Map.replace!(fdmanana, "_rev", third_rev) + + # Cache was refreshed + # BUGGED + # assert_cache(:expect_hit, "fdmanana", "foobar", :expect_login_fail) + # assert_cache(:expect_hit, "fdmanana", "javascript") + + delete_doc(db_name, fdmanana) + + assert_cache(:expect_hit, "fdmanana", "javascript", :expect_login_fail) + + # login, compact authentication DB, login again and verify that + # there was a cache hit + assert_cache(:expect_hit, "johndoe", "123456") + compact(db_name) + wait_until_compact_complete(db_name) + assert_cache(:expect_hit, "johndoe", "123456") + end +end |