Skip to content

Instantly share code, notes, and snippets.

@benoitc
Created February 22, 2014 10:19
Show Gist options
  • Save benoitc/9151625 to your computer and use it in GitHub Desktop.
Save benoitc/9151625 to your computer and use it in GitHub Desktop.
patches for erlcloud/erlcloud#55
From f4e7c10492b7b6f6fd805d4059eb44c4ae8eaa8e Mon Sep 17 00:00:00 2001
From: benoitc <[email protected]>
Date: Sun, 22 Dec 2013 08:44:38 +0100
Subject: [PATCH 1/2] add hackney dependency
---
rebar.config | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/rebar.config b/rebar.config
index 3f82f2b..e1e1e96 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,4 +1,13 @@
+%% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ft=erlang ts=4 sw=4 et
+
{erl_opts, [debug_info]}.
-{deps, [{meck, ".*", {git, "https://github.com/eproxus/meck.git", "master"}},
- {jsx, ".*", {git, "git://github.com/talentdeficit/jsx.git", "master"}}]}.
+{deps, [
+ {meck, ".*",
+ {git, "https://github.com/eproxus/meck.git", "master"}},
+ {jsx, ".*",
+ {git, "https://github.com/talentdeficit/jsx.git", "master"}},
+ {hackney, ".*",
+ {git, "https://github.com/benoitc/hackney.git", "master"}}
+]}.
--
1.8.3.2
From 2b13c3a572eb49a6ffde8ab4273ef2da8ed5e50c Mon Sep 17 00:00:00 2001
From: benoitc <[email protected]>
Date: Sun, 22 Dec 2013 11:10:40 +0100
Subject: [PATCH 2/2] s/httpc/hackney
Just some changes to replace httpc by hackney
---
include/erlcloud_aws.hrl | 3 +-
src/erlcloud_aws.erl | 88 +++++++++---------
src/erlcloud_ddb_impl.erl | 86 +++++++++++-------
src/erlcloud_mturk.erl | 15 ++--
src/erlcloud_s3.erl | 48 ++++++----
test/erlcloud_aws_tests.erl | 17 ++--
test/erlcloud_ddb2_tests.erl | 190 +++++++++++++++++++--------------------
test/erlcloud_ddb_tests.erl | 156 ++++++++++++++++----------------
test/erlcloud_ddb_util_tests.erl | 28 +++---
test/erlcloud_ec2_tests.erl | 40 ++++-----
test/erlcloud_sdb_tests.erl | 6 +-
11 files changed, 360 insertions(+), 317 deletions(-)
diff --git a/include/erlcloud_aws.hrl b/include/erlcloud_aws.hrl
index 12f510f..7fce430 100644
--- a/include/erlcloud_aws.hrl
+++ b/include/erlcloud_aws.hrl
@@ -17,6 +17,7 @@
access_key_id::string()|undefined|false,
secret_access_key::string()|undefined|false,
security_token=undefined::string()|undefined,
- timeout=10000::timeout()
+ timeout=10000::timeout(),
+ pool=default
}).
-type(aws_config() :: #aws_config{}).
diff --git a/src/erlcloud_aws.erl b/src/erlcloud_aws.erl
index 3bedbc0..7fdc683 100644
--- a/src/erlcloud_aws.erl
+++ b/src/erlcloud_aws.erl
@@ -5,13 +5,13 @@
aws_request2/7,
aws_request_xml2/5, aws_request_xml2/7,
param_list/2, default_config/0, update_config/1, format_timestamp/1,
- http_headers_body/1,
sign_v4/5]).
+-export([http_headers_body/1]).
-include("erlcloud.hrl").
-include_lib("erlcloud/include/erlcloud_aws.hrl").
--record(metadata_credentials,
+-record(metadata_credentials,
{access_key_id :: string(),
secret_access_key :: string(),
security_token=undefined :: string(),
@@ -76,38 +76,40 @@ aws_request2_no_update(Method, Protocol, Host, Port, Path, Params, #aws_config{}
undefined -> [];
Token -> [{"SecurityToken", Token}]
end),
-
+
QueryToSign = erlcloud_http:make_query_string(QParams),
RequestToSign = [string:to_upper(atom_to_list(Method)), $\n,
string:to_lower(Host), $\n, Path, $\n, QueryToSign],
Signature = base64:encode(erlcloud_util:sha_mac(Config#aws_config.secret_access_key, RequestToSign)),
-
+
Query = [QueryToSign, "&Signature=", erlcloud_http:url_encode(Signature)],
-
+
case Protocol of
undefined -> UProtocol = "https://";
_ -> UProtocol = [Protocol, "://"]
end,
-
+
case Port of
undefined -> URL = [UProtocol, Host, Path];
_ -> URL = [UProtocol, Host, $:, port_to_str(Port), Path]
end,
-
- %% Note: httpc MUST be used with {timeout, timeout()} option
+
+ %% Note: hacknet MUST be used with {recv_timeout, timeout()} option
%% Many timeout related failures is observed at prod env
%% when library is used in 24/7 manner
Response =
- case Method of
- get ->
- Req = lists:flatten([URL, $?, Query]),
- httpc:request(get, {Req, []}, [{timeout, Config#aws_config.timeout}], []);
- _ ->
- httpc:request(Method,
- {lists:flatten(URL), [], "application/x-www-form-urlencoded; charset=utf-8",
- list_to_binary(Query)}, [{timeout, Config#aws_config.timeout}], [])
- end,
-
+ case Method of
+ get ->
+ URL1 = list_to_binary(lists:flatten([URL, $?, Query])),
+ hackney:get(URL, [], <<>>, [{recv_timeout, Config#aws_config.timeout}]);
+ _ ->
+ URL1 = list_to_binary(URL),
+ hackney:request(Method, URL,
+ [{<<"Content-Type">>,<<"application/x-www-form-urlencoded; charset=utf-8">>}],
+ list_to_binary(Query),
+ [{recv_timeout, Config#aws_config.timeout}])
+ end,
+
http_body(Response).
param_list([], _Key) -> [];
@@ -185,18 +187,18 @@ get_metadata_credentials() ->
timestamp_to_gregorian_seconds(Timestamp) ->
{ok, [Yr, Mo, Da, H, M, S], []} = io_lib:fread("~d-~d-~dT~d:~d:~dZ", binary_to_list(Timestamp)),
calendar:datetime_to_gregorian_seconds({{Yr, Mo, Da}, {H, M, S}}).
-
+
-spec get_credentials_from_metadata() -> {ok, #metadata_credentials{}} | {error, term()}.
get_credentials_from_metadata() ->
%% TODO this function should retry on errors getting credentials
%% First get the list of roles
- case http_body(httpc:request("http://169.254.169.254/latest/meta-data/iam/security-credentials/")) of
+ case http_body(hackney:get("http://169.254.169.254/latest/meta-data/iam/security-credentials/")) of
{error, Reason} ->
{error, Reason};
{ok, Body} ->
%% Always use the first role
Role = string:sub_word(Body, 1, $\n),
- case http_body(httpc:request(
+ case http_body(hackney:get(
"http://169.254.169.254/latest/meta-data/iam/security-credentials/" ++ Role)) of
{error, Reason} ->
{error, Reason};
@@ -219,26 +221,32 @@ port_to_str(Port) when is_list(Port) ->
Port.
-spec http_body({ok, tuple()} | {error, term()}) -> {ok, string()} | {error, tuple()}.
-%% Extract the body and do error handling on the return of a httpc:request call.
-http_body(Return) ->
- case http_headers_body(Return) of
- {ok, {_, Body}} ->
- {ok, Body};
- {error, Reason} ->
- {error, Reason}
+%% Extract the body and do error handling on the return.
+http_body(Resp) ->
+ case Resp of
+ {ok, _, _, Ref} -> hackney:body(Ref);
+ Error -> Error
end.
--type headers() :: [{string(), string()}].
--spec http_headers_body({ok, tuple()} | {error, term()}) -> {ok, {headers(), string()}} | {error, tuple()}.
-%% Extract the headers and body and do error handling on the return of a httpc:request call.
-http_headers_body({ok, {{_HTTPVer, OKStatus, _StatusLine}, Headers, Body}})
- when OKStatus >= 200, OKStatus =< 299 ->
- {ok, {Headers, Body}};
-http_headers_body({ok, {{_HTTPVer, Status, StatusLine}, _Headers, Body}}) ->
- {error, {http_error, Status, StatusLine, Body}};
+http_headers_body({ok, Status, RespHeaders, Ref})
+ when Status >= 200, Status =< 299 ->
+ case hackney:body(Ref) of
+ {ok, Body} ->
+ {ok, RespHeaders, Body};
+ Error ->
+ Error
+ end;
+http_headers_body({ok, Status, _, Ref}) ->
+ case hackney:body(Ref) of
+ {ok, Body} ->
+ {error, {http_error, Status, Body}};
+ Error ->
+ Error
+ end;
http_headers_body({error, Reason}) ->
{error, {socket_error, Reason}}.
+
%% http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
%% TODO additional parameters - currently only supports what is needed for DynamoDB
-spec sign_v4(aws_config(), headers(), binary(), string(), string()) -> headers().
@@ -256,7 +264,7 @@ sign_v4(Config, Headers, Payload, Region, Service) ->
Signature = base16(erlcloud_util:sha256_mac( SigningKey, ToSign)),
Authorization = authorization(Config, CredentialScope, SignedHeaders, Signature),
[{"Authorization", lists:flatten(Authorization)} | Headers2].
-
+
iso_8601_basic_time() ->
{{Year,Month,Day},{Hour,Min,Sec}} = calendar:now_to_universal_time(os:timestamp()),
lists:flatten(io_lib:format(
@@ -294,13 +302,13 @@ base16(Data) ->
credential_scope(Date, Region, Service) ->
DateOnly = string:left(Date, 8),
[DateOnly, $/, Region, $/, Service, "/aws4_request"].
-
+
to_sign(Date, CredentialScope, Request) ->
["AWS4-HMAC-SHA256\n",
Date, $\n,
CredentialScope, $\n,
hash_encode(Request)].
-
+
signing_key(Config, Date, Region, Service) ->
%% TODO cache the signing key so we don't have to recompute for every request
DateOnly = string:left(Date, 8),
@@ -308,7 +316,7 @@ signing_key(Config, Date, Region, Service) ->
KRegion = erlcloud_util:sha256_mac( KDate, Region),
KService = erlcloud_util:sha256_mac( KRegion, Service),
erlcloud_util:sha256_mac( KService, "aws4_request").
-
+
authorization(Config, CredentialScope, SignedHeaders, Signature) ->
["AWS4-HMAC-SHA256"
" Credential=", Config#aws_config.access_key_id, $/, CredentialScope, $,,
diff --git a/src/erlcloud_ddb_impl.erl b/src/erlcloud_ddb_impl.erl
index 9229951..26ba12e 100644
--- a/src/erlcloud_ddb_impl.erl
+++ b/src/erlcloud_ddb_impl.erl
@@ -80,7 +80,7 @@ request(Config0, Operation, Json) ->
%% Sleep after an attempt
-spec backoff(pos_integer()) -> ok.
backoff(1) -> ok;
-backoff(Attempt) ->
+backoff(Attempt) ->
timer:sleep(random:uniform((1 bsl (Attempt - 1)) * 100)).
-type attempt() :: {attempt, pos_integer()} | {error, term()}.
@@ -91,51 +91,74 @@ retry(Attempt, Reason) when Attempt >= ?NUM_ATTEMPTS ->
retry(Attempt, _) ->
backoff(Attempt),
{attempt, Attempt + 1}.
-
+
-type headers() :: [{string(), string()}].
--spec request_and_retry(aws_config(), headers(), jsx:json_text(), attempt()) ->
+-spec request_and_retry(aws_config(), headers(), jsx:json_text(), attempt()) ->
{ok, jsx:json_term()} | {error, term()}.
request_and_retry(_, _, _, {error, Reason}) ->
{error, Reason};
request_and_retry(Config, Headers, Body, {attempt, Attempt}) ->
RetryFun = Config#aws_config.ddb_retry,
- case httpc:request(post, {url(Config), Headers, "application/x-amz-json-1.0", Body},
- [{timeout, 1000}],
- [{body_format, binary}]) of
- {ok, {{_, 200, _}, _, RespBody}} ->
+ Hdrs = [{<<"Content-Type">>, <<"application/x-amz-json-1.0">>} | Headers],
+ case hackney:post(post, url(Config), Hdrs, Body, [{recv_timeout, 1000}]) of
+
+ {ok, 200, _, Ref} ->
%% TODO check crc
- {ok, jsx:decode(RespBody)};
+ case hackney:body(Ref) of
+ {ok, RespBody} -> {ok, jsx:decode(RespBody)};
+ Error -> Error
+ end;
- {ok, {{_, Status, StatusLine}, _, RespBody}} when Status >= 400 andalso Status < 500 ->
- case client_error(Status, StatusLine, RespBody) of
- {retry, Reason} ->
- request_and_retry(Config, Headers, Body, RetryFun(Attempt, Reason));
+ {ok, Status, _, Ref} when Status >= 400 andalso Status < 500 ->
+ case hackney:body(Ref) of
+ {ok, RespBody} ->
+
+ case client_error(Status, RespBody) of
+ {retry, Reason} ->
+ request_and_retry(Config, Headers, Body,
+ RetryFun(Attempt, Reason));
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ request_and_retry(Config, Headers, Body,
+ RetryFun(Attempt, Reason))
+ end;
+ {ok, Status, _, Ref} when Status >= 500 ->
+ case hackney:body(Ref) of
+ {ok, RespBody} ->
+ request_and_retry(Config, Headers, Body,
+ RetryFun(Attempt, {http_error, Status, RespBody}));
{error, Reason} ->
- {error, Reason}
+ request_and_retry(Config, Headers, Body,
+ RetryFun(Attempt, Reason))
+ end;
+
+ {ok, Status, _, Ref} ->
+ case hackney:body(Ref) of
+ {ok, RespBody} ->
+ {error, {http_error, Status, RespBody}};
+ {error, Reason} ->
+ request_and_retry(Config, Headers, Body,
+ RetryFun(Attempt, Reason))
end;
-
- {ok, {{_, Status, StatusLine}, _, RespBody}} when Status >= 500 ->
- request_and_retry(Config, Headers, Body, RetryFun(Attempt, {http_error, Status, StatusLine, RespBody}));
-
- {ok, {{_, Status, StatusLine}, _, RespBody}} ->
- {error, {http_error, Status, StatusLine, RespBody}};
-
{error, Reason} ->
- %% TODO there may be some http errors, such as certificate error, that we don't want to retry
+ %% TODO there may be some http errors, such as certificate
+ %% error, that we don't want to retry
request_and_retry(Config, Headers, Body, RetryFun(Attempt, Reason))
end.
--spec client_error(pos_integer(), string(), binary()) -> {retry, term()} | {error, term()}.
-client_error(Status, StatusLine, Body) ->
+-spec client_error(pos_integer(), binary()) -> {retry, term()} | {error, term()}.
+client_error(Status, Body) ->
case jsx:is_json(Body) of
false ->
- {error, {http_error, Status, StatusLine, Body}};
+ {error, {http_error, Status, Body}};
true ->
Json = jsx:decode(Body),
case proplists:get_value(<<"__type">>, Json) of
undefined ->
- {error, {http_error, Status, StatusLine, Body}};
+ {error, {http_error, Status, Body}};
FullType ->
Message = proplists:get_value(<<"message">>, Json, <<>>),
case binary:split(FullType, <<"#">>) of
@@ -146,21 +169,21 @@ client_error(Status, StatusLine, Body) ->
[_, Type] ->
{error, {Type, Message}};
_ ->
- {error, {http_error, Status, StatusLine, Body}}
+ {error, {http_error, Status, Body}}
end
end
end.
-spec headers(aws_config(), string(), binary()) -> headers().
headers(Config, Operation, Body) ->
- Headers = [{"host", Config#aws_config.ddb_host},
- {"x-amz-target", Operation}],
- Region =
+ Headers = [{<<"host">>, hackney_bstr:to_binary(Config#aws_config.ddb_host)},
+ {<<"x-amz-target">>, hackney_bstr:to_binary(Operation)}],
+ Region =
case string:tokens(Config#aws_config.ddb_host, ".") of
[_, Value, _, _] ->
- Value;
+ hackney_bstr:to_binary(Value);
_ ->
- "us-east-1"
+ <<"us-east-1">>
end,
erlcloud_aws:sign_v4(Config, Headers, Body, Region, "dynamodb").
@@ -171,4 +194,3 @@ port_spec(#aws_config{ddb_port=80}) ->
"";
port_spec(#aws_config{ddb_port=Port}) ->
[":", erlang:integer_to_list(Port)].
-
diff --git a/src/erlcloud_mturk.erl b/src/erlcloud_mturk.erl
index 5580ebb..3b843a8 100644
--- a/src/erlcloud_mturk.erl
+++ b/src/erlcloud_mturk.erl
@@ -1607,16 +1607,13 @@ mturk_request(Config, Operation, Params) ->
{"Signature", Signature}|Params],
URL = ["https://", Config#aws_config.mturk_host, "/"],
+ Hdrs = [{<<"Content-Type">>, <<"application/x-www-form-urlencoded">>}],
+ ReqBody = list_to_binary(erlcloud_http:make_query_string(QParams)),
+ Response = hackney:request(post, lists:flatten(URL), Hdrs, ReqBody, []),
- Response = httpc:request(post,
- {lists:flatten(URL), [], "application/x-www-form-urlencoded",
- list_to_binary(erlcloud_http:make_query_string(QParams))}, [], []),
-
- case Response of
- {ok, {{_HTTPVer, 200, _StatusLine}, _Headers, Body}} ->
+ case erlcloud:http_headers_body(Response) of
+ {ok, _, Body} ->
Body;
- {ok, {{_HTTPVer, Status, _StatusLine}, _Headers, _Body}} ->
- erlang:error({aws_error, {http_error, Status, _StatusLine, _Body}});
{error, Error} ->
- erlang:error({aws_error, {socket_error, Error}})
+ erlang:error({aws_error, Error})
end.
diff --git a/src/erlcloud_s3.erl b/src/erlcloud_s3.erl
index 2c0af4a..a2a5eb5 100644
--- a/src/erlcloud_s3.erl
+++ b/src/erlcloud_s3.erl
@@ -880,25 +880,31 @@ s3_xml_request2(Config, Method, Host, Path, Subresource, Params, POSTData, Heade
Error
end.
-s3_request2_no_update(Config, Method, Host, Path, Subresource, Params, POSTData, Headers0) ->
- {ContentMD5, ContentType, Body} =
- case POSTData of
- {PD, CT} -> {base64:encode(erlcloud_util:md5(PD)), CT, PD}; PD -> {"", "", PD}
- end,
+s3_request2_no_update(Config, Method, Host, Path, Subresource,
+ Params, POSTData, Headers0) ->
+ {ContentMD5, ContentType, Body} = case POSTData of
+ {PD, CT} -> {base64:encode(erlcloud_util:md5(PD)), CT, PD};
+ PD -> {<<"">>, <<"">>, PD}
+ end,
Headers = case Config#aws_config.security_token of
- undefined -> Headers0;
- Token when is_list(Token) -> [{"x-amz-security-token", Token} | Headers0]
- end,
- FHeaders = [Header || {_, Value} = Header <- Headers, Value =/= undefined],
- AmzHeaders = [Header || {"x-amz-" ++ _, _} = Header <- FHeaders],
+ undefined -> Headers0;
+ Token when is_list(Token) ->
+ [{<<"x-amz-security-token">>, hackney_bstr:to_binary(Token)}
+ | Headers0]
+ end,
+ FHeaders = [{hackney_bstr:to_binary(K),hackney_bstr:to_binary(V)}
+ || {K, V} <- Headers, V =/= undefined],
+ AmzHeaders = [Header || {<<"x-amz-", _/binary>>, _} = Header <- FHeaders],
Date = httpd_util:rfc1123_date(erlang:localtime()),
EscapedPath = erlcloud_http:url_encode_loose(Path),
Authorization = make_authorization(Config, Method, ContentMD5, ContentType,
Date, AmzHeaders, Host, EscapedPath, Subresource, Params),
- RequestHeaders = [{"date", Date}, {"authorization", Authorization}|FHeaders] ++
+ RequestHeaders = [{<<"date">>, hackney_bstr:to_binary(Date)},
+ {<<"authorization">>,
+ hackney_bstr:to_binary(Authorization)} | FHeaders] ++
case ContentMD5 of
- "" -> [];
- _ -> [{"content-md5", binary_to_list(ContentMD5)}]
+ <<"">> -> [];
+ _ -> [{<<"content-md5">>, ContentMD5}]
end,
RequestURI = lists:flatten([
Config#aws_config.s3_scheme,
@@ -914,11 +920,17 @@ s3_request2_no_update(Config, Method, Host, Path, Subresource, Params, POSTData,
]),
Response = case Method of
- get -> httpc:request(Method, {RequestURI, RequestHeaders}, [], []);
- head -> httpc:request(Method, {RequestURI, RequestHeaders}, [], []);
- delete -> httpc:request(Method, {RequestURI, RequestHeaders}, [], []);
- _ -> httpc:request(Method, {RequestURI, RequestHeaders, ContentType, Body}, [], [])
- end,
+ get ->
+ hackney:request(Method, RequestURI, RequestHeaders, <<>>, []);
+ head ->
+ hackney:request(Method, RequestURI, RequestHeaders, <<>>, []);
+ delete ->
+ hackney:request(Method, RequestURI, RequestHeaders, <<>>, []);
+ _ ->
+ Hdrs = [{<<"Content-Type">>, ContentType} | RequestHeaders],
+ hackney:request(Method, RequestURI, Hdrs, Body, [])
+ end,
+
erlcloud_aws:http_headers_body(Response).
make_authorization(Config, Method, ContentMD5, ContentType, Date, AmzHeaders,
diff --git a/test/erlcloud_aws_tests.erl b/test/erlcloud_aws_tests.erl
index d44f1cc..1ac3f77 100644
--- a/test/erlcloud_aws_tests.erl
+++ b/test/erlcloud_aws_tests.erl
@@ -10,33 +10,36 @@ request_test_() ->
fun request_prot_host_port_int_test/1]}.
start() ->
- meck:new(httpc, [unstick]),
- meck:expect(httpc, request, fun(_) -> {ok, {{0, 200, 0}, 0, ok}} end),
+ meck:new(hackney, [unstick]),
+ meck:expect(hackney, request, fun(_) -> {ok, 200, 0, ok} end),
+ meck:expect(hackney, get, fun(_) -> {ok, 200, 0, ok} end),
+ meck:expect(hackney, post, fun(_) -> {ok, 200, 0, ok} end),
+
ok.
stop(_) ->
- meck:unload(httpc).
+ meck:unload(hackney).
request_default_test(_) ->
ok = erlcloud_aws:aws_request(get, "host", "/", [], "id", "key"),
- Url = get_url_from_history(meck:history(httpc)),
+ Url = get_url_from_history(meck:history(hackney)),
test_url(https, "host", 443, "/", Url).
request_prot_host_port_str_test(_) ->
ok = erlcloud_aws:aws_request(get, "http", "host1", "9999", "/path1", [], "id", "key"),
- Url = get_url_from_history(meck:history(httpc)),
+ Url = get_url_from_history(meck:history(hackney)),
test_url(http, "host1", 9999, "/path1", Url).
request_prot_host_port_int_test(_) ->
ok = erlcloud_aws:aws_request(get, "http", "host1", 9999, "/path1", [], "id", "key"),
- Url = get_url_from_history(meck:history(httpc)),
+ Url = get_url_from_history(meck:history(hackney)),
test_url(http, "host1", 9999, "/path1", Url).
% ==================
% Internal functions
% ==================
-get_url_from_history([{_, {httpc, request, [Url]}, _}]) ->
+get_url_from_history([{_, {hackney, request, [Url]}, _}]) ->
Url.
test_url(ExpScheme, ExpHost, ExpPort, ExpPath, Url) ->
diff --git a/test/erlcloud_ddb2_tests.erl b/test/erlcloud_ddb2_tests.erl
index 07fef0d..39cd600 100644
--- a/test/erlcloud_ddb2_tests.erl
+++ b/test/erlcloud_ddb2_tests.erl
@@ -5,7 +5,7 @@
-include("erlcloud_ddb2.hrl").
%% Unit tests for ddb.
-%% These tests work by using meck to mock httpc. There are two classes of test: input and output.
+%% These tests work by using meck to mock hackney. There are two classes of test: input and output.
%%
%% Input tests verify that different function args produce the desired JSON request.
%% An input test list provides a list of funs and the JSON that is expected to result.
@@ -19,7 +19,7 @@
-define(_f(F), fun() -> F end).
-export([validate_body/2]).
-
+
%%%===================================================================
%%% Test entry points
%%%===================================================================
@@ -58,11 +58,11 @@ operation_test_() ->
]}.
start() ->
- meck:new(httpc, [unstick]),
+ meck:new(hackney, [unstick]),
ok.
stop(_) ->
- meck:unload(httpc).
+ meck:unload(hackney).
%%%===================================================================
%%% Input test helpers
@@ -79,7 +79,7 @@ sort_object(V) ->
%% verifies that the parameters in the body match the expected parameters
-spec validate_body(binary(), expected_body()) -> ok.
validate_body(Body, Expected) ->
- Want = jsx:decode(list_to_binary(Expected), [{post_decode, fun sort_object/1}]),
+ Want = jsx:decode(list_to_binary(Expected), [{post_decode, fun sort_object/1}]),
Actual = jsx:decode(Body, [{post_decode, fun sort_object/1}]),
case Want =:= Actual of
true -> ok;
@@ -88,13 +88,13 @@ validate_body(Body, Expected) ->
end,
?assertEqual(Want, Actual).
-%% returns the mock of the httpc function input tests expect to be called.
+%% returns the mock of the hackney function input tests expect to be called.
%% Validates the request body and responds with the provided response.
-spec input_expect(string(), expected_body()) -> fun().
input_expect(Response, Expected) ->
- fun(post, {_Url, _Headers, _ContentType, Body}, _HTTPOpts, _Opts) ->
+ fun(post, _Url, _Headers, Body}, _Opts) ->
validate_body(Body, Expected),
- {ok, {{0, 200, 0}, 0, list_to_binary(Response)}}
+ {ok, 200, 0, list_to_binary(Response)}
end.
%% input_test converts an input_test specifier into an eunit test generator
@@ -102,10 +102,10 @@ input_expect(Response, Expected) ->
-spec input_test(string(), input_test_spec()) -> tuple().
input_test(Response, {Line, {Description, Fun, Expected}}) when
is_list(Description) ->
- {Description,
+ {Description,
{Line,
fun() ->
- meck:expect(httpc, request, input_expect(Response, Expected)),
+ meck:expect(hackney, request, input_expect(Response, Expected)),
erlcloud_ddb2:configure(string:copies("A", 20), string:copies("a", 40)),
Fun()
end}}.
@@ -121,11 +121,11 @@ input_tests(Response, Tests) ->
%%% Output test helpers
%%%===================================================================
-%% returns the mock of the httpc function output tests expect to be called.
+%% returns the mock of the hackney function output tests expect to be called.
-spec output_expect(string()) -> fun().
output_expect(Response) ->
- fun(post, {_Url, _Headers, _ContentType, _Body}, _HTTPOpts, _Opts) ->
- {ok, {{0, 200, 0}, 0, list_to_binary(Response)}}
+ fun(post, _Url, _Headers, _Body, _Opts) ->
+ {ok, 200, 0, list_to_binary(Response)}
end.
%% output_test converts an output_test specifier into an eunit test generator
@@ -135,7 +135,7 @@ output_test(Fun, {Line, {Description, Response, Result}}) ->
{Description,
{Line,
fun() ->
- meck:expect(httpc, request, output_expect(Response)),
+ meck:expect(hackney, request, output_expect(Response)),
erlcloud_ddb2:configure(string:copies("A", 20), string:copies("a", 40)),
Actual = Fun(),
case Result =:= Actual of
@@ -147,9 +147,9 @@ output_test(Fun, {Line, {Description, Response, Result}}) ->
end}}.
%% output_test(Fun, {Line, {Response, Result}}) ->
%% output_test(Fun, {Line, {"", Response, Result}}).
-
+
%% output_tests converts a list of output_test specifiers into an eunit test generator
--spec output_tests(fun(), [output_test_spec()]) -> [term()].
+-spec output_tests(fun(), [output_test_spec()]) -> [term()].
output_tests(Fun, Tests) ->
[output_test(Fun, Test) || Test <- Tests].
@@ -158,24 +158,24 @@ output_tests(Fun, Tests) ->
%%% Error test helpers
%%%===================================================================
--spec httpc_response(pos_integer(), string()) -> tuple().
-httpc_response(Code, Body) ->
- {ok, {{"", Code, ""}, [], list_to_binary(Body)}}.
-
+-spec hackney_response(pos_integer(), string()) -> tuple().
+hackney_response(Code, Body) ->
+ {ok, Code, [], list_to_binary(Body)}.
+
-type error_test_spec() :: {pos_integer(), {string(), list(), term()}}.
-spec error_test(fun(), error_test_spec()) -> tuple().
error_test(Fun, {Line, {Description, Responses, Result}}) ->
%% Add a bogus response to the end of the request to make sure we don't call too many times
- Responses1 = Responses ++ [httpc_response(200, "TOO MANY REQUESTS")],
+ Responses1 = Responses ++ [hackney_response(200, "TOO MANY REQUESTS")],
{Description,
{Line,
fun() ->
- meck:sequence(httpc, request, 4, Responses1),
+ meck:sequence(hackney, request, 4, Responses1),
erlcloud_ddb2:configure(string:copies("A", 20), string:copies("a", 40)),
Actual = Fun(),
?assertEqual(Result, Actual)
end}}.
-
+
-spec error_tests(fun(), [error_test_spec()]) -> [term()].
error_tests(Fun, Tests) ->
[error_test(Fun, Test) || Test <- Tests].
@@ -197,21 +197,21 @@ input_exception_test_() ->
%% Error handling tests based on:
%% http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ErrorHandling.html
error_handling_tests(_) ->
- OkResponse = httpc_response(200, "
+ OkResponse = hackney_response(200, "
{\"Item\":
{\"friends\":{\"SS\":[\"Lynda\", \"Aaron\"]},
\"status\":{\"S\":\"online\"}
},
\"ConsumedCapacityUnits\": 1
-}"
+}"
),
OkResult = {ok, [{<<"friends">>, [<<"Lynda">>, <<"Aaron">>]},
{<<"status">>, <<"online">>}]},
- Tests =
+ Tests =
[?_ddb_test(
{"Test retry after ProvisionedThroughputExceededException",
- [httpc_response(400, "
+ [hackney_response(400, "
{\"__type\":\"com.amazonaws.dynamodb.v20111205#ProvisionedThroughputExceededException\",
\"message\":\"The level of configured provisioned throughput for the table was exceeded. Consider increasing your provisioning level with the UpdateTable API\"}"
),
@@ -219,18 +219,18 @@ error_handling_tests(_) ->
OkResult}),
?_ddb_test(
{"Test ConditionalCheckFailed error",
- [httpc_response(400, "
+ [hackney_response(400, "
{\"__type\":\"com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException\",
\"message\":\"The expected value did not match what was stored in the system.\"}"
)],
{error, {<<"ConditionalCheckFailedException">>, <<"The expected value did not match what was stored in the system.">>}}}),
?_ddb_test(
{"Test retry after 500",
- [httpc_response(500, ""),
+ [hackney_response(500, ""),
OkResponse],
OkResult})
],
-
+
error_tests(?_f(erlcloud_ddb2:get_item(<<"table">>, {<<"k">>, <<"v">>})), Tests).
@@ -241,13 +241,13 @@ batch_get_item_input_tests(_) ->
[?_ddb_test(
{"BatchGetItem example request",
?_f(erlcloud_ddb2:batch_get_item(
- [{<<"Forum">>,
+ [{<<"Forum">>,
[{<<"Name">>, {s, <<"Amazon DynamoDB">>}},
- {<<"Name">>, {s, <<"Amazon RDS">>}},
+ {<<"Name">>, {s, <<"Amazon RDS">>}},
{<<"Name">>, {s, <<"Amazon Redshift">>}}],
[{attributes_to_get, [<<"Name">>, <<"Threads">>, <<"Messages">>, <<"Views">>]}]},
- {<<"Thread">>,
- [[{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
+ {<<"Thread">>,
+ [[{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"Subject">>, {s, <<"Concurrent reads">>}}]],
[{attributes_to_get, [<<"Tags">>, <<"Message">>]}]}],
[{return_consumed_capacity, total}])), "
@@ -360,7 +360,7 @@ batch_get_item_input_tests(_) ->
input_tests(Response, Tests).
batch_get_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"BatchGetItem example response", "
{
@@ -434,10 +434,10 @@ batch_get_item_output_tests(_) ->
]
}",
{ok, #ddb2_batch_get_item
- {consumed_capacity =
+ {consumed_capacity =
[#ddb2_consumed_capacity{table_name = <<"Forum">>, capacity_units = 3},
#ddb2_consumed_capacity{table_name = <<"Thread">>, capacity_units = 1}],
- responses =
+ responses =
[#ddb2_batch_get_item_response
{table = <<"Forum">>,
items = [[{<<"Name">>, <<"Amazon DynamoDB">>},
@@ -492,19 +492,19 @@ batch_get_item_output_tests(_) ->
}
}",
{ok, #ddb2_batch_get_item
- {responses = [],
- unprocessed_keys =
- [{<<"Forum">>,
+ {responses = [],
+ unprocessed_keys =
+ [{<<"Forum">>,
[[{<<"Name">>, {s, <<"Amazon DynamoDB">>}}],
- [{<<"Name">>, {s, <<"Amazon RDS">>}}],
+ [{<<"Name">>, {s, <<"Amazon RDS">>}}],
[{<<"Name">>, {s, <<"Amazon Redshift">>}}]],
[{attributes_to_get, [<<"Name">>, <<"Threads">>, <<"Messages">>, <<"Views">>]}]},
- {<<"Thread">>,
- [[{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
+ {<<"Thread">>,
+ [[{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"Subject">>, {s, <<"Concurrent reads">>}}]],
[{attributes_to_get, [<<"Tags">>, <<"Message">>]}]}]}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:batch_get_item([{<<"table">>, [{<<"k">>, <<"v">>}]}], [{out, record}])), Tests).
%% BatchWriteItem test based on the API examples:
@@ -647,7 +647,7 @@ batch_write_item_input_tests(_) ->
input_tests(Response, Tests).
batch_write_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"BatchWriteItem example response", "
{
@@ -677,7 +677,7 @@ batch_write_item_output_tests(_) ->
{ok, #ddb2_batch_write_item
{consumed_capacity = [#ddb2_consumed_capacity{table_name = <<"Forum">>, capacity_units = 3}],
item_collection_metrics = undefined,
- unprocessed_items = [{<<"Forum">>,
+ unprocessed_items = [{<<"Forum">>,
[{put, [{<<"Name">>, {s, <<"Amazon ElastiCache">>}},
{<<"Category">>, {s, <<"Amazon Web Services">>}}]}]}]}}}),
?_ddb_test(
@@ -710,7 +710,7 @@ batch_write_item_output_tests(_) ->
}
}",
{ok, #ddb2_batch_write_item
- {consumed_capacity = undefined,
+ {consumed_capacity = undefined,
item_collection_metrics = undefined,
unprocessed_items =
[{<<"Forum">>, [{put, [{<<"Name">>, {s, <<"Amazon DynamoDB">>}},
@@ -761,8 +761,8 @@ batch_write_item_output_tests(_) ->
}
}",
{ok, #ddb2_batch_write_item
- {consumed_capacity = undefined,
- item_collection_metrics =
+ {consumed_capacity = undefined,
+ item_collection_metrics =
[{<<"Table1">>,
[#ddb2_item_collection_metrics
{item_collection_key = <<"value1">>,
@@ -778,7 +778,7 @@ batch_write_item_output_tests(_) ->
]}],
unprocessed_items = []}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:batch_write_item([], [{out, record}])), Tests).
%% CreateTable test based on the API examples:
@@ -793,7 +793,7 @@ create_table_input_tests(_) ->
{<<"Subject">>, s},
{<<"LastPostDateTime">>, s}],
{<<"ForumName">>, <<"Subject">>},
- 5,
+ 5,
5,
[{local_secondary_indexes,
[{<<"LastPostIndex">>, <<"LastPostDateTime">>, keys_only}]}]
@@ -856,7 +856,7 @@ create_table_input_tests(_) ->
{<<"Subject">>, s},
{<<"LastPostDateTime">>, s}],
{<<"ForumName">>, <<"Subject">>},
- 5,
+ 5,
5,
[{local_secondary_indexes,
[{<<"LastPostIndex">>, <<"LastPostDateTime">>, {include, [<<"Author">>, <<"Body">>]}}]}]
@@ -918,7 +918,7 @@ create_table_input_tests(_) ->
<<"Thread">>,
{<<"ForumName">>, s},
<<"ForumName">>,
- 1,
+ 1,
1
)), "
{
@@ -1005,7 +1005,7 @@ create_table_input_tests(_) ->
input_tests(Response, Tests).
create_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"CreateTable example response", "
{
@@ -1080,7 +1080,7 @@ create_table_output_tests(_) ->
item_count = 0,
key_schema = {<<"ForumName">>, <<"LastPostDateTime">>},
projection = keys_only}],
- provisioned_throughput =
+ provisioned_throughput =
#ddb2_provisioned_throughput_description{
last_decrease_date_time = undefined,
last_increase_date_time = undefined,
@@ -1165,7 +1165,7 @@ create_table_output_tests(_) ->
item_count = 0,
key_schema = {<<"ForumName">>, <<"LastPostDateTime">>},
projection = {include, [<<"Author">>, <<"Body">>]}}],
- provisioned_throughput =
+ provisioned_throughput =
#ddb2_provisioned_throughput_description{
last_decrease_date_time = undefined,
last_increase_date_time = undefined,
@@ -1209,7 +1209,7 @@ create_table_output_tests(_) ->
item_count = 0,
key_schema = <<"ForumName">>,
local_secondary_indexes = undefined,
- provisioned_throughput =
+ provisioned_throughput =
#ddb2_provisioned_throughput_description{
last_decrease_date_time = undefined,
last_increase_date_time = undefined,
@@ -1220,7 +1220,7 @@ create_table_output_tests(_) ->
table_size_bytes = 0,
table_status = creating}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:create_table(<<"name">>, [{<<"key">>, s}], <<"key">>, 5, 10)), Tests).
%% DeleteItem test based on the API examples:
@@ -1229,7 +1229,7 @@ delete_item_input_tests(_) ->
Tests =
[?_ddb_test(
{"DeleteItem example request",
- ?_f(erlcloud_ddb2:delete_item(<<"Thread">>,
+ ?_f(erlcloud_ddb2:delete_item(<<"Thread">>,
[{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"Subject">>, {s, <<"How do I update multiple items?">>}}],
[{return_values, all_old},
@@ -1254,7 +1254,7 @@ delete_item_input_tests(_) ->
}),
?_ddb_test(
{"DeleteItem return metrics",
- ?_f(erlcloud_ddb2:delete_item(<<"Thread">>,
+ ?_f(erlcloud_ddb2:delete_item(<<"Thread">>,
{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
[{return_consumed_capacity, total},
{return_item_collection_metrics, size}])), "
@@ -1297,7 +1297,7 @@ delete_item_input_tests(_) ->
input_tests(Response, Tests).
delete_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"DeleteItem example response", "
{
@@ -1357,7 +1357,7 @@ delete_item_output_tests(_) ->
size_estimate_range_gb = {1,2}}
}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:delete_item(<<"table">>, {<<"k">>, <<"v">>}, [{out, record}])), Tests).
%% DeleteTable test based on the API examples:
@@ -1390,7 +1390,7 @@ delete_table_input_tests(_) ->
input_tests(Response, Tests).
delete_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"DeleteTable example response", "
{
@@ -1416,7 +1416,7 @@ delete_table_output_tests(_) ->
table_size_bytes = 0,
table_status = deleting}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:delete_table(<<"name">>)), Tests).
%% DescribeTable test based on the API examples:
@@ -1494,7 +1494,7 @@ describe_table_input_tests(_) ->
input_tests(Response, Tests).
describe_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"DescribeTable example response", "
{
@@ -1569,7 +1569,7 @@ describe_table_output_tests(_) ->
item_count = 0,
key_schema = {<<"ForumName">>, <<"LastPostDateTime">>},
projection = keys_only}],
- provisioned_throughput =
+ provisioned_throughput =
#ddb2_provisioned_throughput_description{
last_decrease_date_time = undefined,
last_increase_date_time = undefined,
@@ -1580,7 +1580,7 @@ describe_table_output_tests(_) ->
table_size_bytes = 0,
table_status = active}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:describe_table(<<"name">>)), Tests).
%% GetItem test based on the API examples:
@@ -1606,7 +1606,7 @@ get_item_input_tests(_) ->
[?_ddb_test(
{"GetItem example request, with fully specified keys",
?_f(erlcloud_ddb2:get_item(<<"Thread">>,
- [{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
+ [{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"Subject">>, {s, <<"How do I update multiple items?">>}}],
[{attributes_to_get, [<<"LastPostDateTime">>, <<"Message">>, <<"Tags">>]},
consistent_read,
@@ -1617,7 +1617,7 @@ get_item_input_tests(_) ->
Example1Response}),
?_ddb_test(
{"GetItem example request, with inferred key types",
- ?_f(erlcloud_ddb2:get_item(<<"Thread">>,
+ ?_f(erlcloud_ddb2:get_item(<<"Thread">>,
[{<<"ForumName">>, "Amazon DynamoDB"},
{<<"Subject">>, <<"How do I update multiple items?">>}],
[{attributes_to_get, [<<"LastPostDateTime">>, <<"Message">>, <<"Tags">>]},
@@ -1655,7 +1655,7 @@ get_item_input_tests(_) ->
input_tests(Response, Tests).
get_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"GetItem example response", "
{
@@ -1708,15 +1708,15 @@ get_item_output_tests(_) ->
{<<"empty">>, <<>>}],
consumed_capacity = undefined}}}),
?_ddb_test(
- {"GetItem item not found",
+ {"GetItem item not found",
"{}",
{ok, #ddb2_get_item{item = undefined}}}),
?_ddb_test(
- {"GetItem no attributes returned",
+ {"GetItem no attributes returned",
"{\"Item\":{}}",
{ok, #ddb2_get_item{item = []}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:get_item(<<"table">>, {<<"k">>, <<"v">>}, [{out, record}])), Tests).
%% ListTables test based on the API examples:
@@ -1733,7 +1733,7 @@ list_tables_input_tests(_) ->
}),
?_ddb_test(
{"ListTables empty request",
- ?_f(erlcloud_ddb2:list_tables()),
+ ?_f(erlcloud_ddb2:list_tables()),
"{}"
})
@@ -1747,7 +1747,7 @@ list_tables_input_tests(_) ->
input_tests(Response, Tests).
list_tables_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"ListTables example response", "
{
@@ -1758,7 +1758,7 @@ list_tables_output_tests(_) ->
{last_evaluated_table_name = <<"Thread">>,
table_names = [<<"Forum">>, <<"Reply">>, <<"Thread">>]}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:list_tables([{out, record}])), Tests).
%% PutItem test based on the API examples:
@@ -1767,7 +1767,7 @@ put_item_input_tests(_) ->
Tests =
[?_ddb_test(
{"PutItem example request",
- ?_f(erlcloud_ddb2:put_item(<<"Thread">>,
+ ?_f(erlcloud_ddb2:put_item(<<"Thread">>,
[{<<"LastPostedBy">>, <<"[email protected]">>},
{<<"ForumName">>, <<"Amazon DynamoDB">>},
{<<"LastPostDateTime">>, <<"201303190422">>},
@@ -1809,7 +1809,7 @@ put_item_input_tests(_) ->
}),
?_ddb_test(
{"PutItem float inputs",
- ?_f(erlcloud_ddb2:put_item(<<"Thread">>,
+ ?_f(erlcloud_ddb2:put_item(<<"Thread">>,
[{<<"typed float">>, {n, 1.2}},
{<<"untyped float">>, 3.456},
{<<"mixed set">>, {ns, [7.8, 9.0, 10]}}],
@@ -1837,7 +1837,7 @@ put_item_input_tests(_) ->
input_tests(Response, Tests).
put_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"PutItem example response", "
{
@@ -1897,7 +1897,7 @@ put_item_output_tests(_) ->
size_estimate_range_gb = {1,2}}
}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:put_item(<<"table">>, [], [{out, record}])), Tests).
%% Query test based on the API examples:
@@ -2009,7 +2009,7 @@ q_input_tests(_) ->
input_tests(Response, Tests).
q_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"Query example 1 response", "
{
@@ -2103,12 +2103,12 @@ q_output_tests(_) ->
}
}",
{ok, #ddb2_q{count = 17,
- last_evaluated_key =
+ last_evaluated_key =
[{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"Subject">>, {s, <<"Exclusive key can have 3 parts">>}}, {<<"LastPostDateTime">>, {s, <<"20130102054211">>}}]
}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:q(<<"table">>, [{<<"k">>, <<"v">>, eq}], [{out, record}])), Tests).
%% Scan test based on the API examples:
@@ -2125,7 +2125,7 @@ scan_input_tests(_) ->
}),
?_ddb_test(
{"Scan example 2 request",
- ?_f(erlcloud_ddb2:scan(<<"Reply">>,
+ ?_f(erlcloud_ddb2:scan(<<"Reply">>,
[{scan_filter, [{<<"PostedBy">>, <<"[email protected]">>, eq}]},
{return_consumed_capacity, total}])), "
{
@@ -2145,7 +2145,7 @@ scan_input_tests(_) ->
}),
?_ddb_test(
{"Scan exclusive start key",
- ?_f(erlcloud_ddb2:scan(<<"Reply">>,
+ ?_f(erlcloud_ddb2:scan(<<"Reply">>,
[{exclusive_start_key, [{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"LastPostDateTime">>, {n, 20130102054211}}]}])), "
{
@@ -2243,7 +2243,7 @@ scan_input_tests(_) ->
input_tests(Response, Tests).
scan_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"Scan example 1 response", "
{
@@ -2447,7 +2447,7 @@ scan_output_tests(_) ->
{<<"LastPostDateTime">>, {n, 20130102054211}}],
scanned_count = 4}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:scan(<<"name">>, [{out, record}])), Tests).
%% UpdateItem test based on the API examples:
@@ -2456,7 +2456,7 @@ update_item_input_tests(_) ->
Tests =
[?_ddb_test(
{"UpdateItem example request",
- ?_f(erlcloud_ddb2:update_item(<<"Thread">>,
+ ?_f(erlcloud_ddb2:update_item(<<"Thread">>,
[{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"Subject">>, {s, <<"How do I update multiple items?">>}}],
[{<<"LastPostedBy">>, {s, <<"[email protected]">>}, put}],
@@ -2544,7 +2544,7 @@ update_item_input_tests(_) ->
input_tests(Response, Tests).
update_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"UpdateItem example response", "
{
@@ -2585,7 +2585,7 @@ update_item_output_tests(_) ->
}",
{ok, []}})
],
-
+
output_tests(?_f(erlcloud_ddb2:update_item(<<"table">>, {<<"k">>, <<"v">>}, [])), Tests).
%% UpdateTable test based on the API examples:
@@ -2606,7 +2606,7 @@ update_table_input_tests(_) ->
],
Response = "
-{
+{
\"TableDescription\": {
\"AttributeDefinitions\": [
{
@@ -2668,10 +2668,10 @@ update_table_input_tests(_) ->
input_tests(Response, Tests).
update_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"UpdateTable example response", "
-{
+{
\"TableDescription\": {
\"AttributeDefinitions\": [
{
@@ -2744,7 +2744,7 @@ update_table_output_tests(_) ->
item_count = 0,
key_schema = {<<"ForumName">>, <<"LastPostDateTime">>},
projection = keys_only}],
- provisioned_throughput =
+ provisioned_throughput =
#ddb2_provisioned_throughput_description{
last_decrease_date_time = undefined,
last_increase_date_time = 1363801701.282,
@@ -2755,6 +2755,6 @@ update_table_output_tests(_) ->
table_size_bytes = 0,
table_status = updating}}})
],
-
+
output_tests(?_f(erlcloud_ddb2:update_table(<<"name">>, 5, 15)), Tests).
diff --git a/test/erlcloud_ddb_tests.erl b/test/erlcloud_ddb_tests.erl
index 30c1c7a..20dd38e 100644
--- a/test/erlcloud_ddb_tests.erl
+++ b/test/erlcloud_ddb_tests.erl
@@ -5,7 +5,7 @@
-include("erlcloud_ddb.hrl").
%% Unit tests for ddb.
-%% These tests work by using meck to mock httpc. There are two classes of test: input and output.
+%% These tests work by using meck to mock hackney. There are two classes of test: input and output.
%%
%% Input tests verify that different function args produce the desired JSON request.
%% An input test list provides a list of funs and the JSON that is expected to result.
@@ -19,7 +19,7 @@
-define(_f(F), fun() -> F end).
-export([validate_body/2]).
-
+
%%%===================================================================
%%% Test entry points
%%%===================================================================
@@ -58,11 +58,11 @@ operation_test_() ->
]}.
start() ->
- meck:new(httpc, [unstick]),
+ meck:new(hackney, [unstick]),
ok.
stop(_) ->
- meck:unload(httpc).
+ meck:unload(hackney).
%%%===================================================================
%%% Input test helpers
@@ -73,7 +73,7 @@ stop(_) ->
%% verifies that the parameters in the body match the expected parameters
-spec validate_body(binary(), expected_body()) -> ok.
validate_body(Body, Expected) ->
- Want = jsx:decode(list_to_binary(Expected)),
+ Want = jsx:decode(list_to_binary(Expected)),
Actual = jsx:decode(Body),
case Want =:= Actual of
true -> ok;
@@ -82,13 +82,13 @@ validate_body(Body, Expected) ->
end,
?assertEqual(Want, Actual).
-%% returns the mock of the httpc function input tests expect to be called.
+%% returns the mock of the hackney function input tests expect to be called.
%% Validates the request body and responds with the provided response.
-spec input_expect(string(), expected_body()) -> fun().
input_expect(Response, Expected) ->
- fun(post, {_Url, _Headers, _ContentType, Body}, _HTTPOpts, _Opts) ->
+ fun(post, _Url, _Headers, Body, _Opts) ->
validate_body(Body, Expected),
- {ok, {{0, 200, 0}, 0, list_to_binary(Response)}}
+ {ok, 200, 0, list_to_binary(Response)}
end.
%% input_test converts an input_test specifier into an eunit test generator
@@ -96,10 +96,10 @@ input_expect(Response, Expected) ->
-spec input_test(string(), input_test_spec()) -> tuple().
input_test(Response, {Line, {Description, Fun, Expected}}) when
is_list(Description) ->
- {Description,
+ {Description,
{Line,
fun() ->
- meck:expect(httpc, request, input_expect(Response, Expected)),
+ meck:expect(hackney, request, input_expect(Response, Expected)),
erlcloud_ddb:configure(string:copies("A", 20), string:copies("a", 40)),
Fun()
end}}.
@@ -115,11 +115,11 @@ input_tests(Response, Tests) ->
%%% Output test helpers
%%%===================================================================
-%% returns the mock of the httpc function output tests expect to be called.
+%% returns the mock of the hackney function output tests expect to be called.
-spec output_expect(string()) -> fun().
output_expect(Response) ->
- fun(post, {_Url, _Headers, _ContentType, _Body}, _HTTPOpts, _Opts) ->
- {ok, {{0, 200, 0}, 0, list_to_binary(Response)}}
+ fun(post, _Url, _Headers, _Body, _Opts) ->
+ {ok, 200, 0, list_to_binary(Response)}
end.
%% output_test converts an output_test specifier into an eunit test generator
@@ -129,7 +129,7 @@ output_test(Fun, {Line, {Description, Response, Result}}) ->
{Description,
{Line,
fun() ->
- meck:expect(httpc, request, output_expect(Response)),
+ meck:expect(hackney, request, output_expect(Response)),
erlcloud_ddb:configure(string:copies("A", 20), string:copies("a", 40)),
Actual = Fun(),
case Result =:= Actual of
@@ -141,9 +141,9 @@ output_test(Fun, {Line, {Description, Response, Result}}) ->
end}}.
%% output_test(Fun, {Line, {Response, Result}}) ->
%% output_test(Fun, {Line, {"", Response, Result}}).
-
+
%% output_tests converts a list of output_test specifiers into an eunit test generator
--spec output_tests(fun(), [output_test_spec()]) -> [term()].
+-spec output_tests(fun(), [output_test_spec()]) -> [term()].
output_tests(Fun, Tests) ->
[output_test(Fun, Test) || Test <- Tests].
@@ -152,24 +152,24 @@ output_tests(Fun, Tests) ->
%%% Error test helpers
%%%===================================================================
--spec httpc_response(pos_integer(), string()) -> tuple().
-httpc_response(Code, Body) ->
- {ok, {{"", Code, ""}, [], list_to_binary(Body)}}.
-
+-spec hackney_response(pos_integer(), string()) -> tuple().
+hackney_response(Code, Body) ->
+ {ok, Code, [], list_to_binary(Body)}.
+
-type error_test_spec() :: {pos_integer(), {string(), list(), term()}}.
-spec error_test(fun(), error_test_spec()) -> tuple().
error_test(Fun, {Line, {Description, Responses, Result}}) ->
%% Add a bogus response to the end of the request to make sure we don't call too many times
- Responses1 = Responses ++ [httpc_response(200, "TOO MANY REQUESTS")],
+ Responses1 = Responses ++ [hackney_response(200, "TOO MANY REQUESTS")],
{Description,
{Line,
fun() ->
- meck:sequence(httpc, request, 4, Responses1),
+ meck:sequence(hackney, request, 4, Responses1),
erlcloud_ddb:configure(string:copies("A", 20), string:copies("a", 40)),
Actual = Fun(),
?assertEqual(Result, Actual)
end}}.
-
+
-spec error_tests(fun(), [error_test_spec()]) -> [term()].
error_tests(Fun, Tests) ->
[error_test(Fun, Test) || Test <- Tests].
@@ -191,21 +191,21 @@ input_exception_test_() ->
%% Error handling tests based on:
%% http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ErrorHandling.html
error_handling_tests(_) ->
- OkResponse = httpc_response(200, "
+ OkResponse = hackney_response(200, "
{\"Item\":
{\"friends\":{\"SS\":[\"Lynda\", \"Aaron\"]},
\"status\":{\"S\":\"online\"}
},
\"ConsumedCapacityUnits\": 1
-}"
+}"
),
OkResult = {ok, [{<<"friends">>, [<<"Lynda">>, <<"Aaron">>]},
{<<"status">>, <<"online">>}]},
- Tests =
+ Tests =
[?_ddb_test(
{"Test retry after ProvisionedThroughputExceededException",
- [httpc_response(400, "
+ [hackney_response(400, "
{\"__type\":\"com.amazonaws.dynamodb.v20111205#ProvisionedThroughputExceededException\",
\"message\":\"The level of configured provisioned throughput for the table was exceeded. Consider increasing your provisioning level with the UpdateTable API\"}"
),
@@ -213,18 +213,18 @@ error_handling_tests(_) ->
OkResult}),
?_ddb_test(
{"Test ConditionalCheckFailed error",
- [httpc_response(400, "
+ [hackney_response(400, "
{\"__type\":\"com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException\",
\"message\":\"The expected value did not match what was stored in the system.\"}"
)],
{error, {<<"ConditionalCheckFailedException">>, <<"The expected value did not match what was stored in the system.">>}}}),
?_ddb_test(
{"Test retry after 500",
- [httpc_response(500, ""),
+ [hackney_response(500, ""),
OkResponse],
OkResult})
],
-
+
error_tests(?_f(erlcloud_ddb:get_item(<<"table">>, <<"key">>)), Tests).
@@ -235,8 +235,8 @@ batch_get_item_input_tests(_) ->
[?_ddb_test(
{"BatchGetItem example request",
?_f(erlcloud_ddb:batch_get_item(
- [{<<"comp2">>, [<<"Julie">>,
- <<"Mingus">>],
+ [{<<"comp2">>, [<<"Julie">>,
+ <<"Mingus">>],
[{attributes_to_get, [<<"user">>, <<"friends">>]}]},
{<<"comp1">>, [{<<"Casey">>, 1319509152},
{<<"Dave">>, 1319509155},
@@ -277,7 +277,7 @@ batch_get_item_input_tests(_) ->
input_tests(Response, Tests).
batch_get_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"BatchGetItem example response", "
{\"Responses\":
@@ -296,7 +296,7 @@ batch_get_item_output_tests(_) ->
\"UnprocessedKeys\":{}
}",
{ok, #ddb_batch_get_item
- {responses =
+ {responses =
[#ddb_batch_get_item_response
{table = <<"comp1">>,
items = [[{<<"status">>, <<"online">>},
@@ -331,17 +331,17 @@ batch_get_item_output_tests(_) ->
}
}",
{ok, #ddb_batch_get_item
- {responses = [],
- unprocessed_keys =
- [{<<"comp2">>, [{s, <<"Julie">>},
- {s, <<"Mingus">>}],
+ {responses = [],
+ unprocessed_keys =
+ [{<<"comp2">>, [{s, <<"Julie">>},
+ {s, <<"Mingus">>}],
[{attributes_to_get, [<<"user">>, <<"friends">>]}]},
{<<"comp1">>, [{{s, <<"Casey">>}, {n, 1319509152}},
{{s, <<"Dave">>}, {n, 1319509155}},
{{s, <<"Riley">>}, {n, 1319509158}}],
[{attributes_to_get, [<<"user">>, <<"status">>]}]}]}}})
],
-
+
output_tests(?_f(erlcloud_ddb:batch_get_item([{<<"table">>, [<<"key">>]}], [{out, record}])), Tests).
%% BatchWriteItem test based on the API examples:
@@ -434,7 +434,7 @@ batch_write_item_input_tests(_) ->
input_tests(Response, Tests).
batch_write_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"BatchWriteItem example response", "
{
@@ -464,7 +464,7 @@ batch_write_item_output_tests(_) ->
}
}",
{ok, #ddb_batch_write_item
- {responses =
+ {responses =
[#ddb_batch_write_item_response
{table = <<"Thread">>,
consumed_capacity_units = 1.0},
@@ -530,7 +530,7 @@ batch_write_item_output_tests(_) ->
{<<"Thread">>, [{put, [{<<"ForumName">>, {s, <<"Amazon DynamoDB">>}},
{<<"Subject">>, {s, <<"DynamoDB Thread 5">>}}]}]}]}}})
],
-
+
output_tests(?_f(erlcloud_ddb:batch_write_item([], [{out, record}])), Tests).
%% CreateTable test based on the API examples:
@@ -563,7 +563,7 @@ create_table_input_tests(_) ->
input_tests(Response, Tests).
create_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"CreateTable example response", "
{\"TableDescription\":
@@ -587,7 +587,7 @@ create_table_output_tests(_) ->
table_name = <<"comp-table">>,
table_status = <<"CREATING">>}}})
],
-
+
output_tests(?_f(erlcloud_ddb:create_table(<<"name">>, {<<"key">>, s}, 5, 10)), Tests).
%% DeleteItem test based on the API examples:
@@ -621,7 +621,7 @@ delete_item_input_tests(_) ->
input_tests(Response, Tests).
delete_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"DeleteItem example response", "
{\"Attributes\":
@@ -637,7 +637,7 @@ delete_item_output_tests(_) ->
{<<"time">>, 200},
{<<"user">>, <<"Mingus">>}]}})
],
-
+
output_tests(?_f(erlcloud_ddb:delete_item(<<"table">>, <<"key">>)), Tests).
%% DeleteTable test based on the API examples:
@@ -646,7 +646,7 @@ delete_table_input_tests(_) ->
Tests =
[?_ddb_test(
{"DeleteTable example request",
- ?_f(erlcloud_ddb:delete_table(<<"Table1">>)),
+ ?_f(erlcloud_ddb:delete_table(<<"Table1">>)),
"{\"TableName\":\"Table1\"}"
})
],
@@ -665,7 +665,7 @@ delete_table_input_tests(_) ->
input_tests(Response, Tests).
delete_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"DeleteTable example response", "
{\"TableDescription\":
@@ -689,7 +689,7 @@ delete_table_output_tests(_) ->
table_name = <<"Table1">>,
table_status = <<"DELETING">>}}})
],
-
+
output_tests(?_f(erlcloud_ddb:delete_table(<<"name">>)), Tests).
%% DescribeTable test based on the API examples:
@@ -698,7 +698,7 @@ describe_table_input_tests(_) ->
Tests =
[?_ddb_test(
{"DescribeTable example request",
- ?_f(erlcloud_ddb:describe_table(<<"Table1">>)),
+ ?_f(erlcloud_ddb:describe_table(<<"Table1">>)),
"{\"TableName\":\"Table1\"}"
})
],
@@ -719,7 +719,7 @@ describe_table_input_tests(_) ->
input_tests(Response, Tests).
describe_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"DescribeTable example response", "
{\"Table\":
@@ -747,7 +747,7 @@ describe_table_output_tests(_) ->
table_size_bytes = 949,
table_status = <<"ACTIVE">>}}})
],
-
+
output_tests(?_f(erlcloud_ddb:describe_table(<<"name">>)), Tests).
%% GetItem test based on the API examples:
@@ -765,14 +765,14 @@ get_item_input_tests(_) ->
Tests =
[?_ddb_test(
{"GetItem example request, with fully specified keys",
- ?_f(erlcloud_ddb:get_item(<<"comptable">>, {{s, <<"Julie">>}, {n, 1307654345}},
+ ?_f(erlcloud_ddb:get_item(<<"comptable">>, {{s, <<"Julie">>}, {n, 1307654345}},
[consistent_read,
{attributes_to_get, [<<"status">>, <<"friends">>]}])),
Example1Response}),
?_ddb_test(
{"GetItem example request, with inferred key types",
- ?_f(erlcloud_ddb:get_item(<<"comptable">>, {"Julie", 1307654345},
- [consistent_read,
+ ?_f(erlcloud_ddb:get_item(<<"comptable">>, {"Julie", 1307654345},
+ [consistent_read,
{attributes_to_get, [<<"status">>, <<"friends">>]}])),
Example1Response}),
?_ddb_test(
@@ -795,7 +795,7 @@ get_item_input_tests(_) ->
input_tests(Response, Tests).
get_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"GetItem example response", "
{\"Item\":
@@ -831,15 +831,15 @@ get_item_output_tests(_) ->
{<<"b">>, <<5,182>>},
{<<"empty">>, <<>>}]}}),
?_ddb_test(
- {"GetItem item not found",
+ {"GetItem item not found",
"{\"ConsumedCapacityUnits\": 0.5}",
{ok, []}}),
?_ddb_test(
- {"GetItem no attributes returned",
+ {"GetItem no attributes returned",
"{\"ConsumedCapacityUnits\":0.5,\"Item\":{}}",
{ok, []}})
],
-
+
output_tests(?_f(erlcloud_ddb:get_item(<<"table">>, <<"key">>)), Tests).
%% ListTables test based on the API examples:
@@ -848,12 +848,12 @@ list_tables_input_tests(_) ->
Tests =
[?_ddb_test(
{"ListTables example request",
- ?_f(erlcloud_ddb:list_tables([{limit, 3}, {exclusive_start_table_name, <<"comp2">>}])),
+ ?_f(erlcloud_ddb:list_tables([{limit, 3}, {exclusive_start_table_name, <<"comp2">>}])),
"{\"ExclusiveStartTableName\":\"comp2\",\"Limit\":3}"
}),
?_ddb_test(
{"ListTables empty request",
- ?_f(erlcloud_ddb:list_tables()),
+ ?_f(erlcloud_ddb:list_tables()),
"{}"
})
@@ -863,7 +863,7 @@ list_tables_input_tests(_) ->
input_tests(Response, Tests).
list_tables_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"ListTables example response",
"{\"LastEvaluatedTableName\":\"comp5\",\"TableNames\":[\"comp3\",\"comp4\",\"comp5\"]}",
@@ -871,7 +871,7 @@ list_tables_output_tests(_) ->
{last_evaluated_table_name = <<"comp5">>,
table_names = [<<"comp3">>, <<"comp4">>, <<"comp5">>]}}})
],
-
+
output_tests(?_f(erlcloud_ddb:list_tables([{out, record}])), Tests).
%% PutItem test based on the API examples:
@@ -880,8 +880,8 @@ put_item_input_tests(_) ->
Tests =
[?_ddb_test(
{"PutItem example request",
- ?_f(erlcloud_ddb:put_item(<<"comp5">>,
- [{<<"time">>, 300},
+ ?_f(erlcloud_ddb:put_item(<<"comp5">>,
+ [{<<"time">>, 300},
{<<"feeling">>, <<"not surprised">>},
{<<"user">>, <<"Riley">>}],
[{return_values, all_old},
@@ -899,8 +899,8 @@ put_item_input_tests(_) ->
}),
?_ddb_test(
{"PutItem float inputs",
- ?_f(erlcloud_ddb:put_item(<<"comp5">>,
- [{<<"time">>, 300},
+ ?_f(erlcloud_ddb:put_item(<<"comp5">>,
+ [{<<"time">>, 300},
{<<"typed float">>, {n, 1.2}},
{<<"untyped float">>, 3.456},
{<<"mixed set">>, {ns, [7.8, 9.0, 10]}}],
@@ -926,7 +926,7 @@ put_item_input_tests(_) ->
input_tests(Response, Tests).
put_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"PutItem example response", "
{\"Attributes\":
@@ -939,7 +939,7 @@ put_item_output_tests(_) ->
{<<"time">>, 300},
{<<"user">>, <<"Riley">>}]}})
],
-
+
output_tests(?_f(erlcloud_ddb:put_item(<<"table">>, [])), Tests).
%% Query test based on the API examples:
@@ -998,7 +998,7 @@ q_input_tests(_) ->
input_tests(Response, Tests).
q_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"Query example 1 response", "
{\"Count\":2,\"Items\":[{
@@ -1044,7 +1044,7 @@ q_output_tests(_) ->
last_evaluated_key = undefined,
consumed_capacity_units = 1}}})
],
-
+
output_tests(?_f(erlcloud_ddb:q(<<"table">>, <<"key">>, [{out, record}])), Tests).
%% Scan test based on the API examples:
@@ -1053,7 +1053,7 @@ scan_input_tests(_) ->
Tests =
[?_ddb_test(
{"Scan example 1 request",
- ?_f(erlcloud_ddb:scan(<<"1-hash-rangetable">>)),
+ ?_f(erlcloud_ddb:scan(<<"1-hash-rangetable">>)),
"{\"TableName\":\"1-hash-rangetable\"}"
}),
?_ddb_test(
@@ -1100,7 +1100,7 @@ scan_input_tests(_) ->
input_tests(Response, Tests).
scan_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"Scan example 1 response", "
{\"Count\":4,\"Items\":[{
@@ -1198,7 +1198,7 @@ scan_output_tests(_) ->
scanned_count = 2,
consumed_capacity_units = 0.5}}})
],
-
+
output_tests(?_f(erlcloud_ddb:scan(<<"name">>, [{out, record}])), Tests).
%% UpdateItem test based on the API examples:
@@ -1254,7 +1254,7 @@ update_item_input_tests(_) ->
input_tests(Response, Tests).
update_item_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"UpdateItem example response", "
{\"Attributes\":
@@ -1269,7 +1269,7 @@ update_item_output_tests(_) ->
{<<"time">>, 1307654350},
{<<"user">>, <<"Julie">>}]}})
],
-
+
output_tests(?_f(erlcloud_ddb:update_item(<<"table">>, <<"key">>, [])), Tests).
%% UpdateTable test based on the API examples:
@@ -1302,7 +1302,7 @@ update_table_input_tests(_) ->
input_tests(Response, Tests).
update_table_output_tests(_) ->
- Tests =
+ Tests =
[?_ddb_test(
{"UpdateTable example response", "
{\"TableDescription\":
@@ -1329,6 +1329,6 @@ update_table_output_tests(_) ->
table_name = <<"comp1">>,
table_status = <<"UPDATING">>}}})
],
-
+
output_tests(?_f(erlcloud_ddb:update_table(<<"name">>, 5, 15)), Tests).
diff --git a/test/erlcloud_ddb_util_tests.erl b/test/erlcloud_ddb_util_tests.erl
index c1deb2a..7bf9f3c 100644
--- a/test/erlcloud_ddb_util_tests.erl
+++ b/test/erlcloud_ddb_util_tests.erl
@@ -5,7 +5,7 @@
-include("erlcloud_ddb.hrl").
%% Unit tests for erlcloud_ddb_util.
-%% These tests work by using meck to mock httpc.
+%% These tests work by using meck to mock hackney.
%%
%% Input tests verify that different function args produce the desired JSON request.
%% An input test list provides a list of funs and the JSON that is expected to result.
@@ -17,7 +17,7 @@
-define(_ddb_test(T), {?LINE, T}).
%% The _f macro is a terse way to wrap code in a fun. Similar to _test but doesn't annotate with a line number
-define(_f(F), fun() -> F end).
-
+
%%%===================================================================
%%% Test entry points
%%%===================================================================
@@ -32,11 +32,11 @@ operation_test_() ->
]}.
start() ->
- meck:new(httpc, [unstick]),
+ meck:new(hackney, [unstick]),
ok.
stop(_) ->
- meck:unload(httpc).
+ meck:unload(hackney).
%%%===================================================================
%%% Multi-call test helpers
@@ -47,22 +47,22 @@ stop(_) ->
-type response_body() :: string().
-type http_call() :: {expected_body(), response_body()}.
-%% returns the mock of the httpc function multi-call tests expect to be called.
+%% returns the mock of the hackney function multi-call tests expect to be called.
-spec multi_call_expect([http_call(),...]) -> fun().
multi_call_expect([{Expected, Response} | TCalls]) ->
- fun(post, {_Url, _Headers, _ContentType, Body}, _HTTPOpts, _Opts) ->
+ fun(post, _Url, _Headers, Body, _Opts) ->
erlcloud_ddb2_tests:validate_body(Body, Expected),
case TCalls of
[] ->
%% No more calls expected
- meck:delete(httpc, request, 4);
+ meck:delete(hackney, request, 4);
_ ->
%% Set up the expectation for the next call
- meck:expect(httpc, request, multi_call_expect(TCalls))
+ meck:expect(hackney, request, multi_call_expect(TCalls))
end,
- {ok, {{0, 200, 0}, 0, list_to_binary(Response)}}
+ {ok, 200, 0, list_to_binary(Response)}}
end.
-
+
%% mutil_call_test converts a multi_call_test specifier into an eunit test generator
-type multi_call_test_spec() :: {pos_integer(), {description(), fun(), [http_call()], term()}}.
@@ -71,7 +71,7 @@ multi_call_test({Line, {Description, Fun, Calls, Result}}) ->
{Description,
{Line,
fun() ->
- meck:expect(httpc, request, multi_call_expect(Calls)),
+ meck:expect(hackney, request, multi_call_expect(Calls)),
erlcloud_ddb:configure(string:copies("A", 20), string:copies("a", 40)),
Actual = Fun(),
case Result =:= Actual of
@@ -81,9 +81,9 @@ multi_call_test({Line, {Description, Fun, Calls, Result}}) ->
end,
?assertEqual(Result, Actual)
end}}.
-
+
%% multi_call_tests converts a list of multi_call_test specifiers into an eunit test generator
--spec multi_call_tests([multi_call_test_spec()]) -> [term()].
+-spec multi_call_tests([multi_call_test_spec()]) -> [term()].
multi_call_tests(Tests) ->
[multi_call_test(Test) || Test <- Tests].
@@ -456,7 +456,7 @@ q_all_tests(_) ->
\"S\": \"rk2\"
}
}
-}"},
+}"},
{"
{
\"TableName\": \"tn\",
diff --git a/test/erlcloud_ec2_tests.erl b/test/erlcloud_ec2_tests.erl
index 5d6bd80..b5eb525 100644
--- a/test/erlcloud_ec2_tests.erl
+++ b/test/erlcloud_ec2_tests.erl
@@ -5,7 +5,7 @@
-include("erlcloud_ec2.hrl").
%% Unit tests for ec2.
-%% These tests work by using meck to mock httpc. There are two classes of test: input and output.
+%% These tests work by using meck to mock hackney. There are two classes of test: input and output.
%%
%% Input tests verify that different function args produce the desired query parameters.
%% An input test list provides a list of funs and the parameters that are expected to result.
@@ -17,7 +17,7 @@
-define(_ec2_test(T), {?LINE, T}).
%% The _f macro is a terse way to wrap code in a fun. Similar to _test but doesn't annotate with a line number
-define(_f(F), fun() -> F end).
-
+
%%%===================================================================
%%% Test entry points
%%%===================================================================
@@ -30,11 +30,11 @@ describe_tags_test_() ->
fun describe_tags_output_tests/1]}.
start() ->
- meck:new(httpc, [unstick]),
+ meck:new(hackney, [unstick]),
ok.
stop(_) ->
- meck:unload(httpc).
+ meck:unload(hackney).
%%%===================================================================
%%% Input test helpers
@@ -58,7 +58,7 @@ common_params() ->
-spec validate_param(string(), [expected_param()]) -> [expected_param()].
validate_param(Param, Expected) ->
case string:tokens(Param, "=") of
- [Key, Value] ->
+ [Key, Value] ->
ok;
[Key] ->
Value = "",
@@ -72,7 +72,7 @@ validate_param(Param, Expected) ->
%?debugFmt("EXPECTED ~p~nEXPECTED1 ~p", [Expected, Expected1]),
case length(Expected) - 1 =:= length(Expected1) of
true -> ok;
- false ->
+ false ->
?debugFmt("Parameter not expected: ~p", [{Key, Value}])
end,
?assertEqual(length(Expected) - 1, length(Expected1)),
@@ -86,13 +86,13 @@ validate_params(Body, Expected) ->
Remain = lists:foldl(fun validate_param/2, Expected, ParamList),
?assertEqual([], Remain).
-%% returns the mock of the httpc function input tests expect to be called.
+%% returns the mock of the hackney function input tests expect to be called.
%% Validates the query body and responds with the provided response.
-spec input_expect(string(), [expected_param()]) -> fun().
input_expect(Response, Expected) ->
- fun(post, {_Url, [] = _Headers, _ContentType, Body}, [], []) ->
+ fun(post, _Url, [] = _Headers, Body, []) ->
validate_params(Body, Expected),
- {ok, {{0, 200, 0}, 0, Response}}
+ {ok, 200, 0, Response}
end.
%% input_test converts an input_test specifier into an eunit test generator
@@ -100,10 +100,10 @@ input_expect(Response, Expected) ->
-spec input_test(string(), input_test_spec()) -> tuple().
input_test(Response, {Line, {Description, Fun, Params}}) when
is_list(Description) ->
- {Description,
+ {Description,
{Line,
fun() ->
- meck:expect(httpc, request, input_expect(Response, Params)),
+ meck:expect(hackney, request, input_expect(Response, Params)),
%% Configure to make sure there is a key. Would like to do this in start, but
%% that isn't called in the same process
erlcloud_ec2:configure(string:copies("A", 20), string:copies("a", 40)),
@@ -121,11 +121,11 @@ input_tests(Response, Tests) ->
%%% Output test helpers
%%%===================================================================
-%% returns the mock of the httpc function output tests expect to be called.
+%% returns the mock of the hackney function output tests expect to be called.
-spec output_expect(string()) -> fun().
output_expect(Response) ->
- fun(post, {_Url, [] = _Headers, _ContentType, _Body}, [], []) ->
- {ok, {{0, 200, 0}, 0, Response}}
+ fun(post, _Url, [] = _Headers, _Body, []) ->
+ {ok, 200, 0, Response}
end.
%% output_test converts an output_test specifier into an eunit test generator
@@ -135,16 +135,16 @@ output_test(Fun, {Line, {Description, Response, Result}}) ->
{Description,
{Line,
fun() ->
- meck:expect(httpc, request, output_expect(Response)),
+ meck:expect(hackney, request, output_expect(Response)),
erlcloud_ec2:configure(string:copies("A", 20), string:copies("a", 40)),
Actual = Fun(),
?assertEqual(Result, Actual)
end}}.
%% output_test(Fun, {Line, {Response, Result}}) ->
%% output_test(Fun, {Line, {"", Response, Result}}).
-
+
%% output_tests converts a list of output_test specifiers into an eunit test generator
--spec output_tests(fun(), [output_test_spec()]) -> [term()].
+-spec output_tests(fun(), [output_test_spec()]) -> [term()].
output_tests(Fun, Tests) ->
[output_test(Fun, Test) || Test <- Tests].
@@ -210,7 +210,7 @@ describe_tags_input_tests(_) ->
input_tests(Response, Tests).
describe_tags_output_tests(_) ->
- Tests =
+ Tests =
[?_ec2_test(
{"This example describes all the tags in your account.", "
<DescribeTagsResponse xmlns=\"http://ec2.amazonaws.com/doc/2012-12-01/\">
@@ -246,7 +246,7 @@ describe_tags_output_tests(_) ->
<key>database_server</key>
<value/>
</item>
- <item>
+ <item>
<resourceId>i-12345678</resourceId>
<resourceType>instance</resourceType>
<key>stack</key>
@@ -281,6 +281,6 @@ describe_tags_output_tests(_) ->
</DescribeTagsResponse>",
{ok, [#ec2_tag{resource_id="ami-1a2b3c4d", resource_type="image", key="webserver", value=""},
#ec2_tag{resource_id="ami-1a2b3c4d", resource_type="image", key="stack", value="Production"}]}})],
-
+
%% Remaining AWS API examples return subsets of the same data
output_tests(?_f(erlcloud_ec2:describe_tags()), Tests).
diff --git a/test/erlcloud_sdb_tests.erl b/test/erlcloud_sdb_tests.erl
index fa868c0..f366ee1 100644
--- a/test/erlcloud_sdb_tests.erl
+++ b/test/erlcloud_sdb_tests.erl
@@ -7,15 +7,15 @@
setup() ->
erlcloud_sdb:configure("fake", "fake-secret"),
- meck:new(httpc, [unstick]).
+ meck:new(hackney, [unstick]).
cleanup(_) ->
- meck:unload(httpc).
+ meck:unload(hackney).
%% Helpers
expect_chain([Response | Chain]) ->
- meck:expect(httpc, request,
+ meck:expect(hackney, request,
fun(_, _, _, _) ->
expect_chain(Chain),
Response
--
1.8.3.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment