Skip to content

Commit ea49f6c

Browse files
committed
Implement more tests
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 9a36714 commit ea49f6c

File tree

7 files changed

+242
-6
lines changed

7 files changed

+242
-6
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ jobs:
107107
108108
# Run stubs
109109
- name: Run HTTP stub (Windows)
110-
run: cmd /c "start /b node test\http\stub.js" && Start-Sleep -Seconds 5
110+
run: cmd /c "start /b node test\http\stub.js" && Start-Sleep -Seconds 10
111111
if: runner.os == 'windows'
112112
- name: Run HTTP stub (*nix)
113-
run: (node test/http/stub.js &) && sleep 5
113+
run: (node test/http/stub.js &) && sleep 10
114114
if: runner.os != 'windows'
115115

116116
# Not every CTest version supports the --test-dir option. If such option

src/http/include/sourcemeta/hydra/http_request.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
namespace sourcemeta::hydra::http {
2121

22+
// TODO: Support passing a request body
2223
class SOURCEMETA_HYDRA_HTTP_EXPORT Request {
2324
public:
2425
Request(std::string url);

src/http/include/sourcemeta/hydra/http_response.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class SOURCEMETA_HYDRA_HTTP_EXPORT Response {
2323

2424
auto status() const noexcept -> Status;
2525
auto header(const std::string &key) const -> std::optional<std::string>;
26+
auto empty() noexcept -> bool;
2627
auto body() -> std::istringstream &;
2728

2829
private:

src/http/include/sourcemeta/hydra/http_stream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
namespace sourcemeta::hydra::http {
2222

23+
// TODO: Unit test the streaming interface
2324
class SOURCEMETA_HYDRA_HTTP_EXPORT Stream {
2425
public:
2526
Stream(std::string url);

src/http/response.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <sourcemeta/hydra/http_response.h>
22
#include <sourcemeta/hydra/http_status.h>
33

4+
#include <cassert> // assert
45
#include <map> // std::map
56
#include <optional> // std::optional, std::nullopt
67
#include <sstream> // std::ostringstream, std::istringstream
@@ -26,6 +27,11 @@ auto Response::header(const std::string &key) const
2627
return this->headers_.at(key);
2728
}
2829

29-
auto Response::body() -> std::istringstream & { return this->stream_; }
30+
auto Response::empty() noexcept -> bool { return this->stream_.peek() == -1; }
31+
32+
auto Response::body() -> std::istringstream & {
33+
assert(!this->empty());
34+
return this->stream_;
35+
}
3036

3137
} // namespace sourcemeta::hydra::http

test/http/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# Tests
1+
# TODO: Add HTTP/2 tests
2+
23
add_executable(sourcemeta_hydra_http_unit
34
request_1_1_test.cc)
45
sourcemeta_hydra_add_compile_options(sourcemeta_hydra_http_unit)

test/http/request_1_1_test.cc

Lines changed: 228 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,237 @@
1+
#include <algorithm>
2+
#include <iterator>
3+
#include <sstream>
4+
#include <string>
5+
16
#include <gtest/gtest.h>
27
#include <sourcemeta/hydra/http.h>
38

4-
// TODO: Add more tests
9+
static auto body(sourcemeta::hydra::http::Response &response) -> std::string {
10+
std::ostringstream result;
11+
std::copy(
12+
std::istreambuf_iterator<std::ostringstream::char_type>(response.body()),
13+
std::istreambuf_iterator<std::ostringstream::char_type>(),
14+
std::ostreambuf_iterator<std::ostringstream::char_type>(result));
15+
return result.str();
16+
}
17+
18+
TEST(HTTP_Request_1_1, invalid_url) {
19+
sourcemeta::hydra::http::Request request{"foobarbaz"};
20+
EXPECT_THROW(request.send().get(), sourcemeta::hydra::http::Error);
21+
}
22+
23+
TEST(HTTP_Request_1_1, GET_root) {
24+
sourcemeta::hydra::http::Request request{BASE_URL};
25+
request.method(sourcemeta::hydra::http::Method::GET);
26+
sourcemeta::hydra::http::Response response{request.send().get()};
27+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
28+
EXPECT_FALSE(response.empty());
29+
EXPECT_EQ(body(response), "RECEIVED GET /");
30+
}
31+
32+
TEST(HTTP_Request_1_1, HEAD_root) {
33+
sourcemeta::hydra::http::Request request{BASE_URL};
34+
request.method(sourcemeta::hydra::http::Method::HEAD);
35+
sourcemeta::hydra::http::Response response{request.send().get()};
36+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
37+
EXPECT_TRUE(response.empty());
38+
}
39+
40+
TEST(HTTP_Request_1_1, POST_root) {
41+
sourcemeta::hydra::http::Request request{BASE_URL};
42+
request.method(sourcemeta::hydra::http::Method::POST);
43+
sourcemeta::hydra::http::Response response{request.send().get()};
44+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
45+
EXPECT_FALSE(response.empty());
46+
EXPECT_EQ(body(response), "RECEIVED POST /");
47+
}
48+
49+
TEST(HTTP_Request_1_1, PUT_root) {
50+
sourcemeta::hydra::http::Request request{BASE_URL};
51+
request.method(sourcemeta::hydra::http::Method::PUT);
52+
sourcemeta::hydra::http::Response response{request.send().get()};
53+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
54+
EXPECT_FALSE(response.empty());
55+
EXPECT_EQ(body(response), "RECEIVED PUT /");
56+
}
57+
58+
TEST(HTTP_Request_1_1, DELETE_root) {
59+
sourcemeta::hydra::http::Request request{BASE_URL};
60+
request.method(sourcemeta::hydra::http::Method::DELETE);
61+
sourcemeta::hydra::http::Response response{request.send().get()};
62+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
63+
EXPECT_FALSE(response.empty());
64+
EXPECT_EQ(body(response), "RECEIVED DELETE /");
65+
}
66+
67+
TEST(HTTP_Request_1_1, OPTIONS_root) {
68+
sourcemeta::hydra::http::Request request{BASE_URL};
69+
request.method(sourcemeta::hydra::http::Method::OPTIONS);
70+
sourcemeta::hydra::http::Response response{request.send().get()};
71+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
72+
EXPECT_FALSE(response.empty());
73+
EXPECT_EQ(body(response), "RECEIVED OPTIONS /");
74+
}
75+
76+
TEST(HTTP_Request_1_1, TRACE_root) {
77+
sourcemeta::hydra::http::Request request{BASE_URL};
78+
request.method(sourcemeta::hydra::http::Method::TRACE);
79+
sourcemeta::hydra::http::Response response{request.send().get()};
80+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
81+
EXPECT_FALSE(response.empty());
82+
EXPECT_EQ(body(response), "RECEIVED TRACE /");
83+
}
84+
85+
TEST(HTTP_Request_1_1, PATCH_root) {
86+
sourcemeta::hydra::http::Request request{BASE_URL};
87+
request.method(sourcemeta::hydra::http::Method::PATCH);
88+
sourcemeta::hydra::http::Response response{request.send().get()};
89+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
90+
EXPECT_FALSE(response.empty());
91+
EXPECT_EQ(body(response), "RECEIVED PATCH /");
92+
}
93+
94+
TEST(HTTP_Request_1_1, GET_root_foo_bar) {
95+
sourcemeta::hydra::http::Request request{std::string{BASE_URL} + "/foo/bar"};
96+
request.method(sourcemeta::hydra::http::Method::GET);
97+
sourcemeta::hydra::http::Response response{request.send().get()};
98+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
99+
EXPECT_FALSE(response.empty());
100+
EXPECT_EQ(body(response), "RECEIVED GET /foo/bar");
101+
}
102+
103+
TEST(HTTP_Request_1_1, GET_root_custom_code_string) {
104+
sourcemeta::hydra::http::Request request{BASE_URL};
105+
request.method(sourcemeta::hydra::http::Method::GET);
106+
request.header("X-Code", "400");
107+
sourcemeta::hydra::http::Response response{request.send().get()};
108+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::BAD_REQUEST);
109+
EXPECT_FALSE(response.empty());
110+
EXPECT_EQ(body(response), "RECEIVED GET /");
111+
}
112+
113+
TEST(HTTP_Request_1_1, GET_root_custom_code_integer) {
114+
sourcemeta::hydra::http::Request request{BASE_URL};
115+
request.method(sourcemeta::hydra::http::Method::GET);
116+
request.header("X-Code", 400);
117+
sourcemeta::hydra::http::Response response{request.send().get()};
118+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::BAD_REQUEST);
119+
EXPECT_FALSE(response.empty());
120+
EXPECT_EQ(body(response), "RECEIVED GET /");
121+
}
122+
123+
TEST(HTTP_Request_1_1, GET_root_response_content_type_no_capture) {
124+
sourcemeta::hydra::http::Request request{BASE_URL};
125+
request.method(sourcemeta::hydra::http::Method::GET);
126+
sourcemeta::hydra::http::Response response{request.send().get()};
127+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
128+
EXPECT_FALSE(response.empty());
129+
EXPECT_EQ(body(response), "RECEIVED GET /");
130+
EXPECT_FALSE(response.header("content-type").has_value());
131+
}
132+
133+
TEST(HTTP_Request_1_1, GET_root_response_content_type_capture) {
134+
sourcemeta::hydra::http::Request request{BASE_URL};
135+
request.method(sourcemeta::hydra::http::Method::GET);
136+
request.capture("content-type");
137+
sourcemeta::hydra::http::Response response{request.send().get()};
138+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
139+
EXPECT_FALSE(response.empty());
140+
EXPECT_EQ(body(response), "RECEIVED GET /");
141+
EXPECT_TRUE(response.header("content-type").has_value());
142+
EXPECT_EQ(response.header("content-type").value(), "text/plain");
143+
}
144+
145+
TEST(HTTP_Request_1_1, GET_root_missing_header_with_capture) {
146+
sourcemeta::hydra::http::Request request{BASE_URL};
147+
request.method(sourcemeta::hydra::http::Method::GET);
148+
request.capture("x-foo-bar");
149+
sourcemeta::hydra::http::Response response{request.send().get()};
150+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
151+
EXPECT_FALSE(response.empty());
152+
EXPECT_EQ(body(response), "RECEIVED GET /");
153+
EXPECT_FALSE(response.header("x-foo-bar").has_value());
154+
}
155+
156+
TEST(HTTP_Request_1_1, GET_root_multiple_captures_match) {
157+
sourcemeta::hydra::http::Request request{BASE_URL};
158+
request.method(sourcemeta::hydra::http::Method::GET);
159+
request.capture("content-type");
160+
request.capture("content-length");
161+
sourcemeta::hydra::http::Response response{request.send().get()};
162+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
163+
EXPECT_FALSE(response.empty());
164+
EXPECT_EQ(body(response), "RECEIVED GET /");
165+
EXPECT_TRUE(response.header("content-type").has_value());
166+
EXPECT_TRUE(response.header("content-length").has_value());
167+
EXPECT_EQ(response.header("content-type").value(), "text/plain");
168+
EXPECT_EQ(response.header("content-length").value(), "14");
169+
}
170+
171+
TEST(HTTP_Request_1_1, GET_root_multiple_captures_partial_match) {
172+
sourcemeta::hydra::http::Request request{BASE_URL};
173+
request.method(sourcemeta::hydra::http::Method::GET);
174+
request.capture("content-type");
175+
request.capture("x-foo-bar");
176+
sourcemeta::hydra::http::Response response{request.send().get()};
177+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
178+
EXPECT_FALSE(response.empty());
179+
EXPECT_EQ(body(response), "RECEIVED GET /");
180+
EXPECT_TRUE(response.header("content-type").has_value());
181+
EXPECT_FALSE(response.header("x-foo-bar").has_value());
182+
EXPECT_EQ(response.header("content-type").value(), "text/plain");
183+
}
184+
185+
TEST(HTTP_Request_1_1, GET_root_multiple_captures_match_initializer_list) {
186+
sourcemeta::hydra::http::Request request{BASE_URL};
187+
request.method(sourcemeta::hydra::http::Method::GET);
188+
request.capture({"content-type", "content-length"});
189+
sourcemeta::hydra::http::Response response{request.send().get()};
190+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
191+
EXPECT_FALSE(response.empty());
192+
EXPECT_EQ(body(response), "RECEIVED GET /");
193+
EXPECT_TRUE(response.header("content-type").has_value());
194+
EXPECT_TRUE(response.header("content-length").has_value());
195+
EXPECT_EQ(response.header("content-type").value(), "text/plain");
196+
EXPECT_EQ(response.header("content-length").value(), "14");
197+
}
198+
199+
TEST(HTTP_Request_1_1,
200+
GET_root_multiple_captures_partial_match_initializer_list) {
201+
sourcemeta::hydra::http::Request request{BASE_URL};
202+
request.method(sourcemeta::hydra::http::Method::GET);
203+
request.capture({"content-type", "x-foo-bar"});
204+
sourcemeta::hydra::http::Response response{request.send().get()};
205+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
206+
EXPECT_FALSE(response.empty());
207+
EXPECT_EQ(body(response), "RECEIVED GET /");
208+
EXPECT_TRUE(response.header("content-type").has_value());
209+
EXPECT_FALSE(response.header("x-foo-bar").has_value());
210+
EXPECT_EQ(response.header("content-type").value(), "text/plain");
211+
}
212+
213+
TEST(HTTP_Request_1_1, GET_root_request_header_echo) {
214+
sourcemeta::hydra::http::Request request{BASE_URL};
215+
request.method(sourcemeta::hydra::http::Method::GET);
216+
request.header("x-foo-bar", "foo");
217+
request.capture("x-x-foo-bar");
218+
sourcemeta::hydra::http::Response response{request.send().get()};
219+
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
220+
EXPECT_FALSE(response.empty());
221+
EXPECT_EQ(body(response), "RECEIVED GET /");
222+
EXPECT_TRUE(response.header("x-x-foo-bar").has_value());
223+
EXPECT_EQ(response.header("x-x-foo-bar").value(), "foo");
224+
}
5225

6-
TEST(HTTP_Request_1_1, XXX) {
226+
TEST(HTTP_Request_1_1, GET_root_request_header_mixed_case_echo) {
7227
sourcemeta::hydra::http::Request request{BASE_URL};
8228
request.method(sourcemeta::hydra::http::Method::GET);
229+
request.header("X-Foo-Bar", "foo");
230+
request.capture("x-x-foo-bar");
9231
sourcemeta::hydra::http::Response response{request.send().get()};
10232
EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK);
233+
EXPECT_FALSE(response.empty());
234+
EXPECT_EQ(body(response), "RECEIVED GET /");
235+
EXPECT_TRUE(response.header("x-x-foo-bar").has_value());
236+
EXPECT_EQ(response.header("x-x-foo-bar").value(), "foo");
11237
}

0 commit comments

Comments
 (0)