blob: 6a63dffb0cbd33a96ab36e9980342d54a3c66369 [file] [log] [blame]
defmodule Couch.Session do
@moduledoc """
CouchDB session helpers.
"""
defstruct [:cookie, :error]
def new(cookie, error \\ "") do
%Couch.Session{cookie: cookie, error: error}
end
def logout(sess) do
headers = [
"Content-Type": "application/x-www-form-urlencoded",
"X-CouchDB-WWW-Authenticate": "Cookie",
Cookie: sess.cookie
]
Couch.delete!("/_session", headers: headers)
end
def info(sess) do
headers = [
"Content-Type": "application/x-www-form-urlencoded",
"X-CouchDB-WWW-Authenticate": "Cookie",
Cookie: sess.cookie
]
Couch.get("/_session", headers: headers).body
end
def get(sess, url, opts \\ []), do: go(sess, :get, url, opts)
def get!(sess, url, opts \\ []), do: go!(sess, :get, url, opts)
def put(sess, url, opts \\ []), do: go(sess, :put, url, opts)
def put!(sess, url, opts \\ []), do: go!(sess, :put, url, opts)
def post(sess, url, opts \\ []), do: go(sess, :post, url, opts)
def post!(sess, url, opts \\ []), do: go!(sess, :post, url, opts)
def delete(sess, url, opts \\ []), do: go(sess, :delete, url, opts)
def delete!(sess, url, opts \\ []), do: go!(sess, :delete, url, opts)
# Skipping head/patch/options for YAGNI. Feel free to add
# if the need arises.
def go(%Couch.Session{} = sess, method, url, opts) do
opts = Keyword.merge(opts, cookie: sess.cookie)
Couch.request(method, url, opts)
end
def go!(%Couch.Session{} = sess, method, url, opts) do
opts = Keyword.merge(opts, cookie: sess.cookie)
Couch.request!(method, url, opts)
end
end
defmodule Couch do
use HTTPotion.Base
@moduledoc """
CouchDB library to power test suite.
"""
# These constants are supplied to the underlying HTTP client and control
# how long we will wait before timing out a test. The inactivity timeout
# specifically fires during an active HTTP response and defaults to 10_000
# if not specified. We're defining it to a different value than the
# request_timeout largely just so we know which timeout fired.
@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 = Keyword.put(headers, :"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 process_response_body(headers, body) do
content_type = headers[:"Content-Type"]
if !!content_type and String.match?(content_type, ~r/application\/json/) do
body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps])
else
process_response_body(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