Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Move from EUnit to ETest

Signed-off-by: Johannes Huning <mail@johanneshuning.com>
  • Loading branch information...
commit 90fefa5522e143e176242bced3ab22ff44eaef65 1 parent 52d17ea
@johannesh johannesh authored
View
3  .gitignore
@@ -6,9 +6,6 @@
# Ignore compiled BEAM files.
*.beam
-# Ignore files compiled on-the-fly by EUnit.
-.eunit
-
# Ignore dependencies, use `rebar fetch-deps` prior compilation.
deps/*
View
184 README.md
@@ -1,17 +1,17 @@
-## eunit_http
+## etest_http
-EUnit Assertions for HTTP requests
+ETest Assertions for HTTP responses
## Installation
-Install eunit_http by adding it as a [rebar](https://github.com/basho/rebar) dependency:
+Install etest_http by adding it as a [rebar](https://github.com/basho/rebar) dependency:
```erlang
% rebar.config:
{deps, [
- {eunit_http, ".*", {git, "git://github.com/johannesh/eunit_http.git"}},
+ {etest_http, "", {git, "git://github.com/wooga/etest_http.git"}},
% ...
]}.
```
@@ -22,73 +22,44 @@ Then run `rebar get-deps` to synchronize your dependencies.
## Usage
-First of all make sure you initialize `eunit_http` by a call to `eunit_http:init/0` prior using any of the _request macros_ described further below. For now `eunit_http` wraps the HTTP client `lhttpc`, which requires initialization - this will fortunately change in the near future.
-
The _request macros_ are:
```erlang
-performGet(Url, Args...).
-performPost(Url, Args...).
-performRequest(Method, Url, Args...).
+?perform_get(Url, Args...).
+?perform_post(Url, Args...).
+?perform_request(Method, Url, Args...).
```
-Support for more HTTP verbs may be added in the future.
-
Next, note that all _assertion macros_ perform their checks on a HTTP response record which contains the most important data from the responses received, thus their general form is always: `?assert*(Response, Args...)`.
Your test cases could possibly look something like this:
```erlang
-% my_module_tests.erl
--module (my_module_tests).
+% my_module_test.erl
+-module (my_module_test).
-compile (export_all).
--include_lib ("eunit/include/eunit.hrl").
--include_lib ("eunit_http/include/eunit_http.hrl").
+-include_lib ("etest/include/etest.hrl").
+-include_lib ("etest_http/include/etest_http.hrl").
-something_test_() ->
- eunit_http:init(),
- Response = ?performGet("http://localhost:8080/message/1"),
- [?_assertStatus(Response, 200), ?_assertContains("Hello World")].
+something_test() ->
+ Response = ?perform_get("http://localhost:8080/message/1"),
+ ?assert_status(Response, 200),
+ ?assert_contains("Hello World").
```
-Or you could use a setup/teardown approach:
-
-```erlang
-% my_module2_tests.erl
--module (my_module2_tests).
--compile (export_all).
--include_lib ("eunit/include/eunit.hrl").
--include_lib ("eunit_http/include/eunit_http.hrl").
-
-my_module2_test_() ->
- {foreach, fun start/0, fun stop/1, [fun test_first_/1, fun test_second_/1]}.
-
-start() -> eunit_http:init().
-stop(_) -> application:stop(eunit_http).
-
-test_first_(_) ->
- Res = ?performGet("http://localhost:8080/profile/bob"),
- [?_assertStatus(Res, 200), ?_assertContains("This is you!")].
-
-test_second_(_) ->
- Res = ?performGet("http://localhost:8080/profile/alice"),
- [?_assertHeader(Res, 301), ?_assertHeaderVal(Res, <<"Location">>, <<"/login">>)].
-```
-
-The excellent [Learn You Some Erlang](http://learnyousomeerlang.com/eunit#eunit-whats-a-eunit) has more on EUnit in general.
### Request Macros
Assertion macros operate on a _response record_, obtainable via the request macros.
-#### performGet
+#### perform_get
Perform a `GET` request, yielding a response record.
```erlang
-Res = ?performGet(Url).
-Res = ?performGet(Url, Headers).
-Res = ?performGet(Url, Headers, Queries).
+Res = ?perform_get(Url).
+Res = ?perform_get(Url, Headers).
+Res = ?perform_get(Url, Headers, Queries).
% Url = string()
% header() :: {string() | binary() | atom(), string() | binary()}
@@ -99,15 +70,15 @@ Res = ?performGet(Url, Headers, Queries).
****
-#### performPost
+#### perform_post
Perform a `POST` request, yielding a response record.
```erlang
-Res = ?performPost(Url).
-Res = ?performPost(Url, Headers).
-Res = ?performPost(Url, Headers, Body).
-Res = ?performPost(Url, Headers, Body, Queries).
+Res = ?perform_post(Url).
+Res = ?perform_post(Url, Headers).
+Res = ?perform_post(Url, Headers, Body).
+Res = ?perform_post(Url, Headers, Body, Queries).
% Url = string()
% header() :: {string() | binary() | atom(), string() | binary()}
@@ -122,16 +93,16 @@ Res = ?performPost(Url, Headers, Body, Queries).
All assertions macros are available as _test macros_ and _test generator macros_.
-#### assertContains
+#### assert_contains
-Assert that the `Haystack` contains the `Needle`, fail with `assertContains_failed` otherwise.
+Assert that the `Haystack` contains the `Needle`, fail with `assert_contains` otherwise.
```erlang
% Test Macro.
-?assertContains(Haystack, Needle).
+?assert_contains(Haystack, Needle).
% Test Generator Macro.
-?_assertContains(Haystack, Needle).
+?assert_contains(Haystack, Needle).
% Haystack = string()
% Needle = string()
@@ -139,31 +110,31 @@ Assert that the `Haystack` contains the `Needle`, fail with `assertContains_fail
****
-#### assertBodyContains
+#### assert_body_contains
-Assert that the body received with the response `Res` contains the string `Needle`, fail with `assertContains_failed` otherwise too.
+Assert that the body received with the response `Res` contains the string `Needle`, fail with `assert_contains` otherwise too.
```erlang
% Test Macro.
-?assertBodyContains(Res, Needle).
+?assert_body_contains(Res, Needle).
% Test Generator Macro.
-?_assertBodyContains(Res, Needle).
+?assert_body_contains(Res, Needle).
% Needle = string()
```
****
-#### assertBody
+#### assert_body
-Assert that the body received with the response `Res` is exactly `Body`, fail with `assertEqual_failed` otherwise.
+Assert that the body received with the response `Res` is exactly `Body`, fail with `assert_equal` otherwise.
```erlang
-?assertBody(Res, Body).
+?assert_body(Res, Body).
% Test Generator Macro.
-?_assertBody(Res, Body).
+?assert_body(Res, Body).
% Body = binary()
```
@@ -173,136 +144,119 @@ Assert that the body received with the response `Res` is exactly `Body`, fail wi
****
-#### assertHeader
+#### assert_header
-Assert that the presence of a header `HeaderName` in the headers received with the response `Res`, fail with `assertHeader_failed` otherwise.
+Assert that the presence of a header `HeaderName` in the headers received with the response `Res`, fail with `assert_header` otherwise.
```erlang
% Test Macro.
-?assertHeader(Res, HeaderName).
+?assert_header(Res, HeaderName).
% Test Generator Macro.
-?_assertHeader(Res, HeaderName).
+?assert_header(Res, HeaderName).
% HeaderName = string()
% Examples:
-?_assertHeaderVal("X-Signature").
+?assert_header_val("X-Signature").
```
****
-#### assertHeaderVal
+#### assert_header_val
-Assert that the headers received with the response `Res` has a header `HeaderName` with value `HeaderVal`, fail with `assertHeaderVal_failed` otherwise.
+Assert that the headers received with the response `Res` has a header `HeaderName` with value `HeaderVal`, fail with `assert_header_val` otherwise.
```erlang
% Test Macro.
-?assertHeaderVal(Res, HeaderName, HeaderVal).
+?assert_header_val(Res, HeaderName, HeaderVal).
% Test Generator Macro.
-?_assertHeaderVal(Res, HeaderName, HeaderVal).
+?assert_header_val(Res, HeaderName, HeaderVal).
% HeaderName = string()
% HeaderVal = string()
% Examples:
-?_assertHeaderVal("X-Signature", "42UVoTWYp9I-wdWJsQYUyEXRoCI1wCXmOVPqwdV8LU0=").
+?assert_header_val("X-Signature", "42UVoTWYp9I-wdWJsQYUyEXRoCI1wCXmOVPqwdV8LU0=").
```
-**Planned for future versions:**
-* Support for regular expressions
-
****
-#### assertStatus
+#### assert_status
-Assert that the response's HTTP status code is `StatusCode`, fail with `assertStatus_failed` otherwise.
+Assert that the response's HTTP status code is `StatusCode`, fail with `assert_status` otherwise.
```erlang
% Test Macro.
-?assertStatus(Res, StatusCode).
+?assert_status(Res, StatusCode).
% Test Generator Macro.
-?_assertStatus(Res, StatusCode).
+?assert_status(Res, StatusCode).
% StatusCode = integer()
% Example:
-?assertStatus(Res, 200).
+?assert_status(Res, 200).
```
****
-#### assertJson
+#### assert_json
-Assert that the body received with the response `Res` contains a JSON structure equal to `JsonStruct`, fail with `assertEqual_failed` otherwise.
+Assert that the body received with the response `Res` contains a JSON structure equal to `JsonStruct`, fail with `assert_equal` otherwise.
```erlang
% Test Macro.
-?assertJson(Res, JsonStruct).
+?assert_json(Res, JsonStruct).
% Test Generator Macro.
-?_assertJson(Res, JsonStruct).
+?assert_json(Res, JsonStruct).
% JsonStruct = orddict()
% Example:
-?assertJson(Res, [{message, "Hello World"}]).
+?assert_json(Res, [{message, "Hello World"}]).
```
****
-#### assertJsonKey
+#### assert_json_key
-Assert that the body received with the response `Res` contains a JSON object, which has a key `Key` with arbitrary contents, fail with `assertJsonKey_failed` otherwise.
+Assert that the body received with the response `Res` contains a JSON object, which has a key `Key` with arbitrary contents, fail with `assert_json_key` otherwise.
```erlang
% Test Macro.
-?assertJsonKey(Res, Key).
+?assert_json_key(Res, Key).
% Test Generator Macro.
-?_assertJsonKey(Res, Key).
+?assert_json_key(Res, Key).
% Key = binary() | [binary()]
% Examples:
-?assertJsonKey(Res, <<"message">>).
-?assertJsonKey(Res, [<<"messages">>, <<"en">>]).
+?assert_json_key(Res, <<"message">>).
+?assert_json_key(Res, [<<"messages">>, <<"en">>]).
```
-**Planned for future versions:**
-* Support for regular expressions
-
****
-#### assertJsonVal
+#### assert_json_val
-Assert that the body received with the response `Res` contains a JSON object, which under the key `Key` contains exactly `Val`, fail with `assertJsonVal_failed` otherwise.
+Assert that the body received with the response `Res` contains a JSON object, which under the key `Key` contains exactly `Val`, fail with `assert_json_val` otherwise.
```erlang
% Test Macro.
-?assertJsonVal(Res, Key, Val).
+?assert_json_val(Res, Key, Val).
% Test Generator Macro.
-?_assertJsonVal(Res, Key, Val).
+?assert_json_val(Res, Key, Val).
% Key = binary() | [binary()]
% Val = atom() | binary() | list() | integer() | float() | {list()}
% Examples:
-?assertJsonVal(Res, <<"message">>, <<"Hello World">>).
-?assertJsonVal(Res, <<"should_reload">>, true).
-?assertJsonVal(Res, [<<"messages">>, <<"de">>], <<"Hallo Welt">>).
+?assert_json_val(Res, <<"message">>, <<"Hello World">>).
+?assert_json_val(Res, <<"should_reload">>, true).
+?assert_json_val(Res, [<<"messages">>, <<"de">>], <<"Hallo Welt">>).
```
-
-**Planned for future versions:**
-* Support for regular expressions
-
-
-
-## Notes
-
-* I plan to replace `lhttpc` with the Erlang HTTP Server, as well as `elli`, which will be replaced with the Erlang HTTP Client to minimize dependencies
-
-* JSON is encoded and decoded to and from orddicts, this will change to work with simple proplists instead
View
144 include/etest_http.hrl
@@ -0,0 +1,144 @@
+%% @author Johannes Huning <johannes.huning@wooga.com>
+%% @doc ETest HTTP related assertions.
+-ifndef(ETEST_HTTP_HRL).
+-define(ETEST_HTTP_HRL, true).
+
+
+%% @doc The HTTP response record.
+%% Contains all required fields for the assertions to operate on:
+%% Right now that is nothing but status-code, headers and the body.
+-record (etest_http_res, {
+ status :: non_neg_integer(),
+ headers :: [{binary(), binary() | string()}],
+ body :: binary()
+}).
+
+
+-define (perform_get(Url), ?perform_get(Url, [])).
+-define (perform_get(Url, Headers), ?perform_get(Url, Headers, [])).
+
+-define (perform_get(Url, Headers, Queries),
+ ?perform_request(get, Url, Headers, Queries, <<>>)).
+
+
+-define (perform_post(Url), ?perform_post(Url, [])).
+-define (perform_post(Url, Headers), ?perform_post(Url, Headers, <<>>)).
+-define (perform_post(Url, Headers, Body),
+ ?perform_post(Url, Headers, Body, [])).
+
+-define (perform_post(Url, Headers, Body, Queries),
+ ?perform_request(post, Url, Headers, Queries, Body)).
+
+
+-define (perform_request(Method, Url, Headers, Queries, Body),
+((fun() ->
+ case etest_http:perform_request(Method, Url, Headers, Queries, Body) of
+ {error, Reason} ->
+ .erlang:error({perform_request,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {request,
+ {(??Method), (??Url), (??Headers), (??Queries), (??Body)}},
+ {error, Reason}] });
+ __Response -> __Response
+ end
+end)())).
+
+
+-define (assert_contains(Haystack, Needle),
+((fun() ->
+ case string:str(Haystack, Needle) of
+ 0 -> .erlang:error({assert_contains,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {haystack, (??Haystack)},
+ {needle, (??Needle)}] });
+ _ -> ok
+ end
+end)())).
+
+-define (assert_body_contains(Res, Needle),
+ ?assert_contains(Res#etest_http_res.body, Needle)).
+
+-define (assert_body(Res, Body), ?assert_equal(Body, Res#etest_http_res.body)).
+
+
+-define (assert_header(Res, HeaderName),
+((fun() ->
+ Headers = Res#etest_http_res.headers,
+ case proplists:is_defined(HeaderName, Headers) of
+ false ->
+ .erlang:error({assert_header,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expected, (??HeaderName)}] });
+ _ -> ok
+ end
+end)())).
+
+
+-define (assert_header_val(Res, HeaderName, HeaderVal0),
+((fun(HeaderVal) ->
+ __Headers = Res#etest_http_res.headers,
+ case proplists:get_value(HeaderName, __Headers, undefined) of
+ HeaderVal -> ok;
+ __V -> .erlang:error({assert_header_val,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {header, (??HeaderName)},
+ {expected, (??HeaderVal0)},
+ {value, __V}] })
+ end
+end)(HeaderVal0))).
+
+
+-define (assert_status(Res, StatusCode0),
+((fun(StatusCode) ->
+ case Res#etest_http_res.status of
+ StatusCode -> ok;
+ __V -> .erlang:error({assert_status,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expected, (??StatusCode0)},
+ {value, __V}] })
+ end
+end)(StatusCode0))).
+
+
+-define (assert_json(Res, JsonStruct),
+((fun() ->
+ __Value = etest_http_json:decode(Res#etest_http_res.body),
+ __Expected = etest_http_json:decode(etest_http_json:encode(JsonStruct)),
+ ?assert_equal(__Expected, __Value)
+end)())).
+
+
+-define (assert_json_key(Res, Key),
+((fun() ->
+ __JsonStruct = etest_http_json:decode(Res#etest_http_res.body),
+ case etest_http_json:fetch(Key, __JsonStruct, '__undefined__') of
+ '__undefined__' ->
+ .erlang:error({assert_json_key,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expected, (??Key)},
+ {value, undefined}] });
+ _ -> ok
+ end
+end)())).
+
+
+-define (assert_json_val(Res, Key, Value0),
+((fun(Value) ->
+ __JsonStruct = etest_http_json:decode(Res#etest_http_res.body),
+ case etest_http_json:fetch(Key, __JsonStruct, '__undefined__') of
+ Value -> ok;
+ __V -> .erlang:error({assert_json_val,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expected, (??Value0)},
+ {value, __V}] })
+ end
+end)(Value0))).
+
+-endif. % ETEST_HTTP_HRL.
View
235 include/eunit_http.hrl
@@ -1,235 +0,0 @@
-%% @author Johannes Huning <johannes.huning@wooga.com>
-%% @doc EUnit HTTP related assertions.
--ifndef(EUNIT_HTTP_HRL).
--define(EUNIT_HTTP_HRL, true).
-
-
-%% @doc The HTTP response record.
-%% Contains all required fields for the assertions to operate on:
-%% Right now that is nothing but status-code, headers and the body.
--record (eunit_http_res, {
- status_code :: non_neg_integer(),
- headers :: [{binary(), binary() | string()}],
- body :: binary()
-}).
-
-
-%% @doc Perform a GET-request without headers and queries.
-%% Alias for ?performGet(Url, []).
--define (performGet(Url), ?performGet(Url, [])).
-
-
-%% @doc Perform a GET-request using the specified headers but without queries.
-%% Alias for ?performGet(Url, Headers, []).
--define (performGet(Url, Headers), ?performGet(Url, Headers, [])).
-
-
-%% @doc Perform a GET-request using the specified headers and queries.
-%% Alias for ?performRequest(get, Url, Headers, Queries, <<>>).
--define (performGet(Url, Headers, Queries),
- ?performRequest(get, Url, Headers, Queries, <<>>)).
-
-
-% TODO - Document!
--define (performPost(Url), ?performPost(Url, [])).
-
-% TODO - Document!
--define (performPost(Url, Headers), ?performPost(Url, Headers, <<>>)).
-
-% TODO - Document!
--define (performPost(Url, Headers, Body),
- ?performPost(Url, Headers, Body, [])).
-
-% TODO - Document!
--define (performPost(Url, Headers, Body, Queries),
- ?performRequest(post, Url, Headers, Queries, Body)).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (performRequest(Method, Url, Headers, Queries, Body), ok).
--else.
--define (performRequest(Method, Url, Headers, Queries, Body),
- ((fun() ->
- case eunit_http:perform_request(Method, Url, Headers, Queries, Body) of
- {error, Reason} ->
- .erlang:error({performRequest_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {request, {Method, Url, Headers, Queries, Body}},
- {error, (??Reason)}]});
- __Response -> __Response
- end
- end)())).
--endif.
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertContains(Haystack, Needle), ok).
--else.
--define (assertContains(Haystack, Needle),
- ((fun() ->
- case string:str(Haystack, Needle) of
- 0 -> .erlang:error({assertContains_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {haystack, Haystack},
- {needle, Needle}]});
- _ -> ok
- end
- end)())).
--endif.
-
--define (_assertContains(Haystack, Needle),
- ?_test(?assertContains(Haystack, Needle))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertBodyContains(Res, Needle), ok).
--else.
--define (assertBodyContains(Res, Needle),
- ?assertContains(binary_to_list(Res#eunit_http_res.body), Needle)).
--endif.
-
--define (_assertBodyContains(Res, Needle),
- ?_test(?assertBodyContains(Res, Needle))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertBody(Res, Body), ok).
--else.
--define (assertBody(Res, Body), ?assertEqual(Body, Res#eunit_http_res.body)).
--endif.
-
--define (_assertBody(Res, Body), ?_test(?assertBody(Res, Body))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertHeader(Res, HeaderName), ok).
--else.
--define (assertHeader(Res, HeaderName),
- ((fun() ->
- Headers = Res#eunit_http_res.headers,
- case proplists:is_defined(HeaderName, Headers) of
- false -> .erlang:error({assertHeader_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expected, (??HeaderName)}]});
- _ -> ok
- end
- end)())).
--endif.
-
--define (_assertHeader(Res, HeaderName),
- ?_test(?assertHeader(Res, HeaderName))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertHeaderVal(Res, HeaderName, HeaderVal), ok).
--else.
--define (assertHeaderVal(Res, HeaderName, HeaderVal),
- ((fun() ->
- __Headers = Res#eunit_http_res.headers,
- case proplists:get_value(HeaderName, __Headers, undefined) of
- HeaderVal -> ok;
- __V -> .erlang:error({assertHeaderVal_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expected, HeaderVal},
- {value, __V}]})
- end
- end)())).
--endif.
-
--define (_assertHeaderVal(Res, HeaderName, HeaderVal),
- ?_test(?assertHeaderVal(Res, HeaderName, HeaderVal))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertStatus(Res, StatusCode), ok).
--else.
--define (assertStatus(Res, StatusCode),
- ((fun() ->
- case Res#eunit_http_res.status_code of
- StatusCode -> ok;
- __V -> .erlang:error({assertStatus_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expected, StatusCode},
- {value, __V}]})
- end
- end)())).
--endif.
-
--define (_assertStatus(Res, StatusCode),
- ?_test(?assertStatus(Res, StatusCode))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertJson(Res, JsonStruct), ok).
--else.
--define (assertJson(Res, JsonStruct),
- ((fun() ->
- __Value = eunit_http_json:decode(Res#eunit_http_res.body),
- __Expected = eunit_http_json:decode(eunit_http_json:encode(JsonStruct)),
- ?assertEqual(__Expected, __Value)
- end)())).
--endif.
-
--define (_assertJson(Res, JsonStruct), ?_test(?assertJson(Res, JsonStruct))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertJsonKey(Res, Key), ok).
--else.
--define (assertJsonKey(Res, Key),
- ((fun() ->
- __JsonStruct = eunit_http_json:decode(Res#eunit_http_res.body),
- case eunit_http_json:fetch(Key, __JsonStruct, '__undefined__') of
- '__undefined__' ->
- .erlang:error({assertJsonKey_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {expected, Key},
- {value, undefined}] });
- _ -> ok
- end
- end)())).
--endif.
-
--define (_assertJsonKey(Res, Key), ?_test(?assertJsonKey(Res, Key))).
-
-
-% TODO - Document!
--ifdef(NOASSERT).
--define (assertJsonVal(Res, Key, Val), ok).
--else.
--define (assertJsonVal(Res, Key, Val),
- ((fun(Value) ->
- __JsonStruct = eunit_http_json:decode(Res#eunit_http_res.body),
- case eunit_http_json:fetch(Key, __JsonStruct, '__undefined__') of
- Value ->
- ok;
- __V ->
- .erlang:error({assertJsonVal_failed, [
- {module, ?MODULE},
- {line, ?LINE},
- {expected, Value},
- {value, __V}]
- })
- end
- end)( Val ))).
--endif.
-
--define (_assertJsonVal(Res, Key, Val), ?_test(?assertJsonVal(Res, Key, Val))).
-
-
--endif. % EUNIT_HTTP_HRL.
View
1  priv/first.html
@@ -0,0 +1 @@
+Hello World!
View
12 priv/second.json
@@ -0,0 +1,12 @@
+{
+ "foo": [
+ "bar",
+ "baz",
+ 1,
+ 2,
+ 3
+ ],
+ "bar": {
+ "baz": "bang"
+ }
+}
View
21 rebar.config
@@ -2,25 +2,14 @@
{lib_dirs, ["deps"]}.
% Erlang compiler options.
-{erl_opts, [
- % Include debug information in the form of abstract code in the compiled
- % beam module. Tools such as Debugger, Xref and Cover require the debug
- % information to be included.
- debug_info
-]}.
+{erl_opts, [debug_info, {src_dirs, ["src", "test"]}]}.
-% What dependancies we have, depandencies can be of 3 forms, an application
-% name as an atom, eg. mochiweb, a name and a version (from the .app file), or
-% an application name, a version and the SCM details on how to fetch it (SCM
-% type, location and revision). Rebar currently support git, hg, bzr and svn.
{deps, [
- {lhttpc, "1.2.6", {git, "git://github.com/esl/lhttpc.git", "master"}},
- {jiffy, "", {git, "git://github.com/davisp/jiffy.git"}},
- {elli, "", {git, "git://github.com/johannesh/elli.git"}}
+ % For testing etest_http itself.
+ {etest, ".*", {git, "git://github.com/wooga/etest.git"}},
+ % For JSON encoding, decoding and subsequently comparison.
+ {jiffy, "", {git, "git://github.com/davisp/jiffy.git"}}
]}.
-% Which files to cleanup.
{clean_files, ["ebin/*.beam"]}.
-
-% XRef checks to run.
{xref_checks, [exports_not_used, undefined_function_calls]}.
View
8 src/etest_http.app.src
@@ -0,0 +1,8 @@
+{application, etest_http, [
+ {description, "ETest HTTP Assertions"},
+ {vsn, git},
+ {registered, []},
+ {modules, []},
+ {applications, [kernel, stdlib]},
+ {env, []}
+]}.
View
51 src/etest_http.erl
@@ -0,0 +1,51 @@
+%% @author Johannes Huning <johannes.huning@wooga.com>
+-module (etest_http).
+-export ([perform_request/5]).
+
+-include ("etest_http.hrl").
+
+
+% Erlangs built-in HTTP client requires inets to be running to operate.
+-on_load (init/0).
+init() -> inets:start(), ok.
+
+
+%% @doc Performs a HTTP request,
+%% returning a `etest_http_res` record to assert upon.
+perform_request(Method, Url, Headers, Queries, Body) ->
+ FullUrl = Url ++ query_string(Queries),
+ Request = case Method of
+ get -> {FullUrl, Headers};
+ _ -> {FullUrl, Headers, "", Body}
+ end,
+
+ case httpc:request(Method, Request, [], []) of
+ {ok, Response} ->
+ {{_, StatusCode, _}, ResHeaders, ResBody} = Response,
+ #etest_http_res {
+ status = StatusCode,
+ headers = Headers,
+ body = ResBody };
+
+ Error = {error, _} -> Error
+ end.
+
+
+%% @doc Generates a query string to be appended to ab URL.
+query_string([Head|Tail]) ->
+ "?" ++ [make_query(Head) | [["&", make_query(Elem)] || Elem <- Tail]];
+
+query_string([]) -> [].
+
+
+make_query({Key, Value}) ->
+ [url_encode(Key), "=", url_encode(Value)].
+
+url_encode(Value) when is_list(Value) ->
+ http_uri:encode(Value);
+
+url_encode(Value) when is_bitstring(Value) ->
+ url_encode(binary_to_list(Value));
+
+url_encode(Value) when is_integer(Value) ->
+ Value.
View
48 src/eunit_http_json.erl → src/etest_http_json.erl
@@ -1,9 +1,9 @@
%% @author Johannes Huning <johannes.huning@wooga.com>
%% @doc JSON specific helper functions.
--module (eunit_http_json).
+-module (etest_http_json).
%% Public helper methods.
--export ([encode/1, decode/1, fetch/2, fetch/3]).
+-export ([encode/1, decode/1, fetch/2, fetch/3, construct/1]).
% Insert a new element to the JSON-object.
@@ -32,13 +32,13 @@ construct(Literal) -> Literal.
%% @doc TODO.
fetch([Key|[]], Orddict) ->
- fetch(Key, Orddict);
+ fetch(Key, Orddict);
fetch([Parent|Rest], Orddict) ->
- fetch(Rest, fetch(Parent, Orddict));
+ fetch(Rest, fetch(Parent, Orddict));
fetch(Key, Orddict) ->
- orddict:fetch(Key, Orddict).
+ orddict:fetch(Key, Orddict).
%% @doc Attempt to fetch the fiven Key from the Orddict or return the Default.
@@ -51,51 +51,51 @@ fetch(Key, Dict, Default) ->
% TODO - Document!
encode(Orddict) ->
- jiffy:encode(pack(Orddict)).
+ jiffy:encode(pack(Orddict)).
% TODO - Document!
decode(Binary) ->
- construct(unpack(jiffy:decode(Binary))).
+ construct(unpack(jiffy:decode(Binary))).
%% @doc Attempts to extract a orddict from the given jiffy-JSON.
unpack(Json) when is_list(Json) orelse is_tuple(Json) ->
- unpack(Json, orddict:new());
+ unpack(Json, orddict:new());
%% Only tuples and list require deeper unpacking, return simple structs.
unpack(Json) -> Json.
%% @doc Recursively unpacks a nested jiffy-JSON object.
unpack({Proplist}, Dict) when is_list(Proplist) ->
- lists:foldl(
- fun({Key, Value}, Acc) ->
- orddict:store(Key, unpack(Value), Acc)
- end,
- Dict,
- Proplist
- );
+ lists:foldl(
+ fun({Key, Value}, Acc) ->
+ orddict:store(Key, unpack(Value), Acc)
+ end,
+ Dict,
+ Proplist
+ );
% List of jiffy-JSON => list of unpacked structs.
unpack(List, _) when is_list(List) ->
- [unpack(Elem) || Elem <- List].
+ [unpack(Elem) || Elem <- List].
%% @doc Recursively builds a jiffy-JSON struct from the given orddict.
% Single orddict => jiffy-JSON object.
pack(Orddict = [Head|_]) when is_list(Orddict) andalso is_tuple(Head) ->
- {orddict:fold(
- fun(Key, Value, Acc) ->
- Acc ++ [{Key, pack(Value)}]
- end,
- [],
- Orddict
- )};
+ {orddict:fold(
+ fun(Key, Value, Acc) ->
+ Acc ++ [{Key, pack(Value)}]
+ end,
+ [],
+ Orddict
+ )};
% Treat the empty list as an empty object.
pack([]) -> {[]};
% List of orddicts => list of jiffy-JSON objects.
pack(List) when is_list(List) ->
- [pack(Elem) || Elem <- List];
+ [pack(Elem) || Elem <- List];
pack(undefined) -> null;
View
41 src/eunit_http.app.src
@@ -1,41 +0,0 @@
-{application, eunit_http, [
- % A very short description of your application.
- {description, "EUnit HTTP Assertions"},
-
- % Pull the version number from git.
- {vsn, git},
-
- % All names of registered processes in the application. systools uses this
- % list to detect name clashes between applications.
- {registered, [
- eunit_http_sup
- ]},
-
- % All modules introduced by this application. systools uses this list when
- % generating boot scripts and tar files. A module must be defined in one and
- % only one application. Defaults to [].
- {modules, [
- eunit_http_app,
- eunit_http_sup
- ]},
-
- % All applications which must be started before this application is started.
- % systools uses this list to generate correct boot scripts.
- {applications, [
- kernel,
- stdlib,
- lhttpc
- ]},
-
- % The application controller will automatically load any included applications
- % when loading a primary application, but not start them. Instead, the top
- % supervisor of the included application must be started by a supervisor in
- % the including application.
- {included_applications, []},
-
- % Configuration parameters: A list of {Par, Val} tuples, Par should be
- % an atom, Val may be any term.
- % The values specified here can be overridden by values in a system
- % configuration file.
- {env, []}
-]}.
View
52 src/eunit_http.erl
@@ -1,52 +0,0 @@
-%% @author Johannes Huning <johannes.huning@wooga.com>
-%% @doc Application initialization module.
--module (eunit_http).
--export ([init/0]).
--export ([perform_request/5]).
--include ("eunit_http.hrl").
-
-
-%% @doc Starts eunit_http, including all dependencies.
-init() ->
- Deps = [crypto, public_key, ssl, lhttpc, eunit_http],
- [application:start(Dep) || Dep <- Deps].
-
-
-% TODO - Document!
-perform_request(Method, Url, Headers0, Queries, Body) ->
- FullUrl = Url ++ make_query(Queries),
-
- case lhttpc:request(FullUrl, Method, Headers0, Body, 10000) of
- Error = {error, _} -> Error;
- {ok, Response} ->
- {{StatusCode, _}, Headers, ResponseBody} = Response,
- #eunit_http_res{
- status_code = StatusCode,
- headers = Headers,
- body = ResponseBody
- }
- end.
-
-
-
-make_query([H | T]) ->
- "?" ++ [url_var(H) | [["&", url_var(X)] || X <- T]];
-
-make_query([]) ->
- [].
-
-url_var({Key, Value}) ->
- [query_string(Key), "=", query_string(Value)].
-
-query_string( Value ) when is_list(Value) ->
- http_uri:encode(Value);
-
-query_string( Value ) when is_bitstring(Value) ->
- http_uri:encode(binary_to_list(Value));
-
-query_string( Value ) when is_integer(Value) ->
- Value;
-
-% Catch all - throws badarg
-query_string( Value ) ->
- throw({badarg, "Argument must be either String, Integer or Bitstring"}).
View
33 src/eunit_http_handler.erl
@@ -1,33 +0,0 @@
-%% @author Johannes Huning <johannes.huning@wooga.com>
-%% @doc TODO!
--module (eunit_http_handler).
--behaviour (elli_handler).
--export ([handle/2, handle_event/3]).
-
-% TODO - Document!
--define (HEADERS, [
- {<<"Date">>, <<"Wed, 02 May 2012 13:03:14 GMT">>},
- {<<"Content-Type">>, <<"text/html; charset=utf-8">>} ]).
-
-
-% TODO - Document!
-handle(Req, Args) ->
- handle(elli_request:path(Req), Req, Args).
-
-
-% TODO - Document!
-handle([<<"json">>], _Req, _Args) ->
- JsonStruct = orddict:from_list([
- {foo, [bar, baz, 1, 2, 3]},
- {bar, [
- {baz, bang}
- ]}
- ]),
- {200, ?HEADERS, eunit_http_json:encode(JsonStruct)};
-
-% TODO - Document!
-handle(_, _Req, _Args) -> {200, ?HEADERS, <<"Hello">>}.
-
-
-% TODO - Document!
-handle_event(_Event, _Data, _Args) -> ok.
View
59 test/etest_http_test.erl
@@ -0,0 +1,59 @@
+%% @author Johannes Huning <johannes.huning@wooga.com>
+%% @doc Test of the assertions itself.
+-module (etest_http_test).
+-compile (export_all).
+
+-include_lib ("etest/include/etest.hrl").
+-include_lib ("etest_http/include/etest_http.hrl").
+
+
+before_suite() ->
+ inets:start(),
+ {ok, Pid} = inets:start(httpd, [
+ {port, 59408},
+ {server_name, "etest_httpd"},
+ {server_root, "/tmp"},
+ {ipfamily, inet},
+ {document_root, "priv"} ]),
+ put(server_pid, Pid).
+
+
+after_suite() ->
+ ok = inets:stop(httpd, get(server_pid)).
+
+
+test_response_assertions() ->
+ Res = ?perform_get("http://localhost:59408/first.html"),
+
+ ?assert_status(Res, 200),
+ ?assert_error({assert_status, _}, ?assert_status(Res, 400)),
+
+ ?assert_body_contains(Res, "Hello"),
+ ?assert_error({assert_contains, _}, ?assert_body_contains(Res, "Olleh")),
+
+ ?assert_header(Res, "date"),
+ ?assert_error({assert_header, _}, ?assert_header(Res, "X-Missing")),
+
+ ?assert_header_val(Res, "content-type", "text/html"),
+ ?assert_error({assert_header_val, _},
+ ?assert_header_val(Res, "content-type", "application/json")).
+
+
+test_json_assertions() ->
+ JsonStruct = etest_http_json:construct([
+ {foo, [bar, baz, 1, 2, 3]},
+ {bar, [{baz, bang}]}
+ ]),
+
+ Res = ?perform_get("http://localhost:59408/second.json"),
+
+ ?assert_json(Res, JsonStruct),
+ ?assert_error({assert_equal, _}, ?assert_json(Res, [])),
+
+ ?assert_json_key(Res, <<"foo">>),
+ ?assert_error({assert_json_key, _}, ?assert_json_key(Res, "baz")),
+
+ ?assert_json_val(Res, <<"foo">>, [<<"bar">>, <<"baz">>, 1, 2, 3]),
+ ?assert_json_val(Res, [<<"bar">>, <<"baz">>], <<"bang">>),
+ ?assert_error({assert_json_val, _},
+ ?assert_json_val(Res, <<"foo">>, undefined)).
View
78 test/eunit_http_tests.erl
@@ -1,78 +0,0 @@
-%% @author Johannes Huning <johannes.huning@wooga.com>
-%% @doc TODO!
--module (eunit_http_tests).
--compile (export_all).
--include_lib ("eunit/include/eunit.hrl").
-
-% TODO - Document!
--include_lib ("eunit_http/include/eunit_http.hrl").
-
-
-% TODO - Document!
-eunit_http_test_() ->
- {foreach, fun start/0, fun stop/1, [
- fun resAssertions/1, fun jsonAssertions/1
- ]}.
-
-% TODO - Document!
-start() ->
- eunit_http:init(),
- ElliArgs = [{callback, eunit_http_handler}, {port, 3002}],
- {ok, Pid} = elli:start_link(ElliArgs),
- Pid.
-
-% TODO - Document!
-stop(Pid) ->
- application:stop(eunit_http),
- elli:stop(Pid).
-
-
-% TODO - Document!
-resAssertions(_) ->
- Resps = [?performGet("http://localhost:3002/"),
- ?performPost("http://localhost:3002/")],
-
- Test = fun(Res) -> [
- ?_assertStatus(Res, 200),
- ?_assertError({assertStatus_failed, _}, ?assertStatus(Res, 400)),
-
- ?_assertBodyContains(Res, "Hello"),
- ?_assertError({assertContains_failed, _},
- ?assertBodyContains(Res, "Olleh")),
-
- ?_assertHeader(Res, "Date"),
- ?_assertError({assertHeader_failed, _},
- ?assertHeader(Res, "X-Missing")),
-
- ?_assertHeaderVal(Res, "Content-Type", "text/html; charset=utf-8"),
- ?_assertError({assertHeaderVal_failed, _},
- ?assertHeaderVal(Res, "Content-Type", "application/json"))]
- end,
-
- [Test(R) || R <- Resps].
-
-
-jsonAssertions(_) ->
- Resps = [?performGet("http://localhost:3002/json"),
- ?performPost("http://localhost:3002/json")],
-
- JsonStruct = orddict:from_list([
- {foo, [bar, baz, 1, 2, 3]},
- {bar, [{baz, bang}]}
- ]),
-
- Test = fun(Res) -> [
- ?_assertJson(Res, JsonStruct),
- ?_assertError({assertEqual_failed, _}, ?assertJson(Res, [])),
-
- ?_assertJsonKey(Res, <<"foo">>),
- ?_assertError({assertJsonKey_failed, _}, ?assertJsonKey(Res, "baz")),
-
- ?_assertJsonVal(Res, <<"foo">>, [<<"bar">>, <<"baz">>, 1, 2, 3]),
- ?_assertJsonVal(Res, [<<"bar">>, <<"baz">>], <<"bang">>),
- ?_assertError({assertJsonVal_failed, _},
- ?assertJsonVal(Res, <<"foo">>, undefined))
- ]
- end,
-
- [Test(R) || R <- Resps].
Please sign in to comment.
Something went wrong with that request. Please try again.