Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,14 @@ soak-eunit: couch
while [ $$? -eq 0 ] ; do $(REBAR) -r eunit $(EUNIT_OPTS) ; done

.PHONY: elixir
elixir:
elixir: elixir-check-formatted
@rm -rf dev/lib
@dev/run -a adm:pass --no-eval test/elixir/run

.PHONY: elixir-check-formatted
elixir-check-formatted:
@cd test/elixir/ && mix format --check-formatted

.PHONY: javascript
# target: javascript - Run JavaScript test suites or specific ones defined by suites option
javascript: devclean
Expand Down
5 changes: 4 additions & 1 deletion Makefile.win
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,13 @@ just-eunit:


.PHONY: elixir
elixir:
elixir: elixir-check-formatted
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for updating Makefile.win as well!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, but I have no chance to try it.

@del /s/q dev\lib 2> nul
@dev\run -a adm:pass --no-eval test\elixir\run.cmd

.PHONY: elixir-check-formatted
elixir-check-formatted:
@cd test\elixir && mix format --check-formatted

.PHONY: test-cluster-with-quorum
test-cluster-with-quorum: devclean
Expand Down
6 changes: 6 additions & 0 deletions test/elixir/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
line_length: 120,
rename_deprecated_at: "1.5.0"
]
120 changes: 70 additions & 50 deletions test/elixir/lib/couch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ defmodule Couch.Session do

def logout(sess) do
headers = [
"Content-Type": "application/x-www-form-urlencoded",
"X-CouchDB-WWW-Authenticate": "Cookie",
"Cookie": sess.cookie
]
"Content-Type": "application/x-www-form-urlencoded",
"X-CouchDB-WWW-Authenticate": "Cookie",
Cookie: sess.cookie
]

Couch.delete!("/_session", headers: headers)
end

Expand All @@ -28,17 +29,16 @@ defmodule Couch.Session do
# if the need arises.

def go(%Couch.Session{} = sess, method, url, opts) do
opts = Keyword.merge(opts, [cookie: sess.cookie])
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])
opts = Keyword.merge(opts, cookie: sess.cookie)
Couch.request!(method, url, opts)
end
end


defmodule Couch do
use HTTPotion.Base

Expand All @@ -52,24 +52,27 @@ defmodule Couch do

def process_request_headers(headers, 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

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
Keyword.put(headers, :Cookie, cookie)
end
end


def process_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
Expand All @@ -90,21 +93,21 @@ defmodule Couch do

def process_response_body(headers, body) do
if String.match?(headers[:"Content-Type"], ~r/application\/json/) do
body |> IO.iodata_to_binary |> :jiffy.decode([:return_maps])
body |> IO.iodata_to_binary() |> :jiffy.decode([:return_maps])
else
process_response_body(body)
end
end

def login(userinfo) do
[user, pass] = String.split(userinfo, ":", [parts: 2])
[user, pass] = String.split(userinfo, ":", parts: 2)
login(user, pass)
end

def login(user, pass) do
resp = Couch.post("/_session", body: %{:username => user, :password => pass})
true = resp.body["ok"]
cookie = resp.headers[:'set-cookie']
cookie = resp.headers[:"set-cookie"]
[token | _] = String.split(cookie, ";")
%Couch.Session{cookie: token}
end
Expand All @@ -113,57 +116,74 @@ defmodule Couch do
# https://github.com/myfreeweb/httpotion/commit/f3fa2f0bc3b9b400573942b3ba4628b48bc3c614
def handle_response(response) do
case response do
{ :ok, status_code, headers, body, _ } ->
{:ok, status_code, headers, body, _} ->
processed_headers = process_response_headers(headers)

%HTTPotion.Response{
status_code: process_status_code(status_code),
headers: processed_headers,
body: process_response_body(processed_headers, body)
}
{ :ok, status_code, headers, body } ->

{:ok, status_code, headers, body} ->
processed_headers = process_response_headers(headers)

%HTTPotion.Response{
status_code: process_status_code(status_code),
headers: processed_headers,
body: process_response_body(processed_headers, body)
}
{ :ibrowse_req_id, id } ->
%HTTPotion.AsyncResponse{ id: id }
{ :error, { :conn_failed, { :error, reason }}} ->
%HTTPotion.ErrorResponse{ message: error_to_string(reason)}
{ :error, :conn_failed } ->
%HTTPotion.ErrorResponse{ message: "conn_failed"}
{ :error, reason } ->
%HTTPotion.ErrorResponse{ message: error_to_string(reason)}

{:ibrowse_req_id, id} ->
%HTTPotion.AsyncResponse{id: id}

{:error, {:conn_failed, {:error, reason}}} ->
%HTTPotion.ErrorResponse{message: error_to_string(reason)}

{:error, :conn_failed} ->
%HTTPotion.ErrorResponse{message: "conn_failed"}

{:error, reason} ->
%HTTPotion.ErrorResponse{message: error_to_string(reason)}
end
end

# Anther HACK: Until we can get process_request_headers/2 merged
# upstream.
@spec process_arguments(atom, String.t, [{atom(), any()}]) :: %{}
@spec process_arguments(atom, String.t(), [{atom(), any()}]) :: %{}
defp process_arguments(method, url, options) do
options = process_options(options)

body = Keyword.get(options, :body, "")
headers = Keyword.merge Application.get_env(:httpotion, :default_headers, []), Keyword.get(options, :headers, [])
timeout = Keyword.get(options, :timeout, Application.get_env(:httpotion, :default_timeout, 5000))
ib_options = Keyword.merge Application.get_env(:httpotion, :default_ibrowse, []), Keyword.get(options, :ibrowse, [])
follow_redirects = Keyword.get(options, :follow_redirects, Application.get_env(:httpotion, :default_follow_redirects, false))

ib_options = if stream_to = Keyword.get(options, :stream_to), do: Keyword.put(ib_options, :stream_to, spawn(__MODULE__, :transformer, [stream_to, method, url, options])), else: ib_options
ib_options = if user_password = Keyword.get(options, :basic_auth) do
{user, password} = user_password
Keyword.put(ib_options, :basic_auth, { to_charlist(user), to_charlist(password) })
else
ib_options
end
options = process_options(options)

body = Keyword.get(options, :body, "")
headers = Keyword.merge(Application.get_env(:httpotion, :default_headers, []), Keyword.get(options, :headers, []))
timeout = Keyword.get(options, :timeout, Application.get_env(:httpotion, :default_timeout, 5000))

ib_options =
Keyword.merge(Application.get_env(:httpotion, :default_ibrowse, []), Keyword.get(options, :ibrowse, []))

follow_redirects =
Keyword.get(options, :follow_redirects, Application.get_env(:httpotion, :default_follow_redirects, false))

ib_options =
if stream_to = Keyword.get(options, :stream_to),
do: Keyword.put(ib_options, :stream_to, spawn(__MODULE__, :transformer, [stream_to, method, url, options])),
else: ib_options

ib_options =
if user_password = Keyword.get(options, :basic_auth) do
{user, password} = user_password
Keyword.put(ib_options, :basic_auth, {to_charlist(user), to_charlist(password)})
else
ib_options
end

%{
method: method,
url: url |> to_string |> process_url(options) |> to_charlist,
body: body |> process_request_body,
headers: headers |> process_request_headers(options) |> Enum.map(fn ({k, v}) -> { to_charlist(k), to_charlist(v) } end),
timeout: timeout,
method: method,
url: url |> to_string |> process_url(options) |> to_charlist,
body: body |> process_request_body,
headers:
headers |> process_request_headers(options) |> Enum.map(fn {k, v} -> {to_charlist(k), to_charlist(v)} end),
timeout: timeout,
ib_options: ib_options,
follow_redirects: follow_redirects
}
Expand Down
2 changes: 1 addition & 1 deletion test/elixir/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule Foo.Mixfile do
app: :foo,
version: "0.1.0",
elixir: "~> 1.5",
start_permanent: Mix.env == :prod,
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
Expand Down
28 changes: 19 additions & 9 deletions test/elixir/test/all_docs_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ defmodule AllDocsTest do
@tag :with_db
test "All Docs tests", context do
db_name = context[:db_name]
resp1 = Couch.post("/#{db_name}", [body: %{:_id => "0", :a => 1, :b => 1}]).body
resp2 = Couch.post("/#{db_name}", [body: %{:_id => "3", :a => 4, :b => 16}]).body
resp3 = Couch.post("/#{db_name}", [body: %{:_id => "1", :a => 2, :b => 4}]).body
resp4 = Couch.post("/#{db_name}", [body: %{:_id => "2", :a => 3, :b => 9}]).body
resp1 = Couch.post("/#{db_name}", body: %{:_id => "0", :a => 1, :b => 1}).body
resp2 = Couch.post("/#{db_name}", body: %{:_id => "3", :a => 4, :b => 16}).body
resp3 = Couch.post("/#{db_name}", body: %{:_id => "1", :a => 2, :b => 4}).body
resp4 = Couch.post("/#{db_name}", body: %{:_id => "2", :a => 3, :b => 9}).body

assert resp1["ok"]
assert resp2["ok"]
Expand All @@ -30,6 +30,7 @@ defmodule AllDocsTest do
resp = Couch.get("/#{db_name}/_all_docs").body
rows = resp["rows"]
assert resp["total_rows"] == length(rows)

Enum.each(rows, fn row ->
assert row["id"] >= "0" && row["id"] <= "4"
end)
Expand All @@ -44,14 +45,19 @@ defmodule AllDocsTest do
assert resp["offset"] == 2

# Confirm that queries may assume raw collation
resp = Couch.get("/#{db_name}/_all_docs", query: %{
:startkey => "\"org.couchdb.user:\"",
:endkey => "\"org.couchdb.user;\""
})
resp =
Couch.get("/#{db_name}/_all_docs",
query: %{
:startkey => "\"org.couchdb.user:\"",
:endkey => "\"org.couchdb.user;\""
}
)

assert length(resp.body["rows"]) == 0

# Check that all docs show up in the changes feed; order can vary
resp = Couch.get("/#{db_name}/_changes").body

Enum.each(resp["results"], fn row ->
assert Enum.member?(revs, hd(row["changes"])["rev"]), "doc #{row["id"]} should be in changes"
end)
Expand Down Expand Up @@ -103,7 +109,11 @@ defmodule AllDocsTest do
assert Couch.put("/#{db_name}/3", query: %{:new_edits => false}, body: conflicted_doc2).body["ok"]

win_rev = Couch.get("/#{db_name}/3").body
changes = Couch.get("/#{db_name}/_changes", query: %{:include_docs => true, :conflicts => true, :style => "all_docs"}).body["results"]

changes =
Couch.get("/#{db_name}/_changes", query: %{:include_docs => true, :conflicts => true, :style => "all_docs"}).body[
"results"
]

doc3 = Enum.find(changes, fn row -> row["id"] == "3" end)
assert doc3["id"] == "3"
Expand Down
Loading