webservd: add fake request, mock response for testing request handlers
Change-Id: I26ab8bf01038b4ae9f022bc1001bd7455cb1f986
diff --git a/libwebserv/mock_response.h b/libwebserv/mock_response.h
new file mode 100644
index 0000000..d0f50ff
--- /dev/null
+++ b/libwebserv/mock_response.h
@@ -0,0 +1,58 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef WEBSERVER_LIBWEBSERV_MOCK_RESPONSE_H_
+#define WEBSERVER_LIBWEBSERV_MOCK_RESPONSE_H_
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+
+#include <libwebserv/response.h>
+
+namespace libwebserv {
+
+// Mock Response implementation for testing.
+class MockResponse : public Response {
+ public:
+ MockResponse() = default;
+
+ MOCK_METHOD2(AddHeader, void(const std::string&, const std::string&));
+ MOCK_METHOD1(AddHeaders,
+ void(const std::vector<std::pair<std::string, std::string>>&));
+
+ // Workaround for mocking with move-only StreamPtr.
+ MOCK_METHOD3(MockReply, void(int, brillo::Stream*, const std::string&));
+
+ MOCK_METHOD3(ReplyWithText,
+ void(int, const std::string&, const std::string&));
+ MOCK_METHOD2(ReplyWithJson, void(int, const base::Value*));
+ MOCK_METHOD2(ReplyWithJson,
+ void(int, const std::map<std::string, std::string>&));
+ MOCK_METHOD2(Redirect, void(int, const std::string&));
+ MOCK_METHOD2(ReplyWithError, void(int, const std::string&));
+ MOCK_METHOD0(ReplyWithErrorNotFound, void());
+
+ private:
+ void Reply(int status_code,
+ brillo::StreamPtr data_stream,
+ const std::string &mime_type) override {
+ return MockReply(status_code, data_stream.get(), mime_type);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MockResponse);
+};
+
+} // namespace libwebserv
+
+#endif // WEBSERVER_LIBWEBSERV_MOCK_RESPONSE_H_
diff --git a/libwebserv/protocol_handler.cc b/libwebserv/protocol_handler.cc
index df8c255..73b61db 100644
--- a/libwebserv/protocol_handler.cc
+++ b/libwebserv/protocol_handler.cc
@@ -24,7 +24,7 @@
#include "dbus_bindings/org.chromium.WebServer.RequestHandler.h"
#include "libwebserv/request.h"
#include "libwebserv/request_handler_callback.h"
-#include "libwebserv/response.h"
+#include "libwebserv/response_impl.h"
#include "libwebserv/server.h"
#include "webservd/dbus-proxies.h"
@@ -220,7 +220,7 @@
}
handler_iter->second.handler->HandleRequest(
std::move(request),
- std::unique_ptr<Response>{new Response{this, request_id}});
+ std::unique_ptr<Response>{new ResponseImpl{this, request_id}});
return true;
}
diff --git a/libwebserv/protocol_handler.h b/libwebserv/protocol_handler.h
index ab4a749..ab5e0ac 100644
--- a/libwebserv/protocol_handler.h
+++ b/libwebserv/protocol_handler.h
@@ -127,7 +127,7 @@
private:
friend class FileInfo;
friend class Server;
- friend class Response;
+ friend class ResponseImpl;
using ProtocolHandlerProxy = org::chromium::WebServer::ProtocolHandlerProxy;
diff --git a/libwebserv/request.cc b/libwebserv/request.cc
index f0bdd79..959b294 100644
--- a/libwebserv/request.cc
+++ b/libwebserv/request.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <libwebserv/request.h>
+#include <libwebserv/request_impl.h>
#include <base/callback.h>
#include <brillo/http/http_utils.h>
@@ -45,16 +45,13 @@
error_callback);
}
-Request::Request(ProtocolHandler* handler,
- const std::string& url,
- const std::string& method)
- : handler_{handler}, url_{url}, method_{method} {
+RequestImpl::RequestImpl(ProtocolHandler* handler,
+ const std::string& url,
+ const std::string& method)
+ : Request{url, method}, handler_{handler} {
}
-Request::~Request() {
-}
-
-brillo::StreamPtr Request::GetDataStream() {
+brillo::StreamPtr RequestImpl::GetDataStream() {
return brillo::FileStream::FromFileDescriptor(
raw_data_fd_.GetPlatformFile(), false, nullptr);
}
diff --git a/libwebserv/request.h b/libwebserv/request.h
index 63bea8e..f1f7043 100644
--- a/libwebserv/request.h
+++ b/libwebserv/request.h
@@ -69,9 +69,11 @@
};
// A class that represents the HTTP request data.
-class LIBWEBSERV_EXPORT Request final {
+class LIBWEBSERV_EXPORT Request {
public:
- ~Request();
+ Request(const std::string& url, const std::string& method)
+ : url_{url}, method_{method} {}
+ virtual ~Request() = default;
// Gets the request body data stream. Note that the stream is available
// only for requests that provided data and if this data is not already
@@ -81,7 +83,7 @@
// The stream returned is valid for as long as the Request object itself is
// alive. Accessing the stream after the Request object is destroyed will lead
// to an undefined behavior (will likely just crash).
- brillo::StreamPtr GetDataStream();
+ virtual brillo::StreamPtr GetDataStream() = 0;
// Returns the request path (e.g. "/path/document").
const std::string& GetPath() const { return url_; }
@@ -131,25 +133,13 @@
// An empty string is returned if the header does not exist in the request.
std::string GetFirstHeader(const std::string& name) const;
- private:
- friend class Server;
-
- LIBWEBSERV_PRIVATE Request(ProtocolHandler* handler,
- const std::string& url,
- const std::string& method);
-
- ProtocolHandler* handler_{nullptr};
+ protected:
std::string url_;
std::string method_;
- base::File raw_data_fd_;
- bool last_posted_data_was_file_{false};
-
std::multimap<std::string, std::string> post_data_;
std::multimap<std::string, std::string> get_data_;
std::multimap<std::string, std::unique_ptr<FileInfo>> file_info_;
std::multimap<std::string, std::string> headers_;
-
- DISALLOW_COPY_AND_ASSIGN(Request);
};
} // namespace libwebserv
diff --git a/libwebserv/request_fake.h b/libwebserv/request_fake.h
new file mode 100644
index 0000000..4fd4f20
--- /dev/null
+++ b/libwebserv/request_fake.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef WEBSERVER_LIBWEBSERV_REQUEST_FAKE_H_
+#define WEBSERVER_LIBWEBSERV_REQUEST_FAKE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/callback_forward.h>
+#include <base/files/file.h>
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <brillo/errors/error.h>
+#include <brillo/streams/stream.h>
+#include <libwebserv/export.h>
+#include <libwebserv/request.h>
+
+namespace libwebserv {
+
+// Implementation of Request that allows custom data for testing.
+class RequestFake : public Request {
+ public:
+ RequestFake(const std::string& url, const std::string& method)
+ : Request(url, method) {}
+
+ void SetDataStream(brillo::StreamPtr data_stream) {
+ data_stream_ = std::move(data_stream);
+ }
+
+ void SetFormDataPost(std::multimap<std::string, std::string> post_data) {
+ post_data_ = std::move(post_data);
+ }
+
+ void SetFormDataGet(std::multimap<std::string, std::string> get_data) {
+ get_data_ = std::move(get_data);
+ }
+
+ void SetFileInfo(
+ std::multimap<std::string, std::unique_ptr<FileInfo>> file_info) {
+ file_info_ = std::move(file_info);
+ }
+
+ void SetHeaders(std::multimap<std::string, std::string> headers) {
+ headers_ = std::move(headers);
+ }
+
+ // Overrides from Request.
+ brillo::StreamPtr GetDataStream() override { return std::move(data_stream_); }
+
+ private:
+ brillo::StreamPtr data_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestFake);
+};
+
+} // namespace libwebserv
+
+#endif // WEBSERVER_LIBWEBSERV_REQUEST_FAKE_H_
diff --git a/libwebserv/request_impl.h b/libwebserv/request_impl.h
new file mode 100644
index 0000000..4d99873
--- /dev/null
+++ b/libwebserv/request_impl.h
@@ -0,0 +1,48 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef WEBSERVER_LIBWEBSERV_REQUEST_IMPL_H_
+#define WEBSERVER_LIBWEBSERV_REQUEST_IMPL_H_
+
+#include <string>
+
+#include <base/files/file.h>
+#include <base/macros.h>
+#include <brillo/streams/stream.h>
+#include <libwebserv/request.h>
+
+namespace libwebserv {
+
+// Implementation of the Request interface.
+class RequestImpl final : public Request {
+ public:
+ // Overrides from Request.
+ brillo::StreamPtr GetDataStream() override;
+
+ private:
+ friend class Server;
+
+ LIBWEBSERV_PRIVATE RequestImpl(ProtocolHandler* handler,
+ const std::string& url,
+ const std::string& method);
+ ProtocolHandler* handler_{nullptr};
+ base::File raw_data_fd_;
+ bool last_posted_data_was_file_{false};
+
+ DISALLOW_COPY_AND_ASSIGN(RequestImpl);
+};
+
+} // namespace libwebserv
+
+#endif // WEBSERVER_LIBWEBSERV_REQUEST_IMPL_H_
diff --git a/libwebserv/response.cc b/libwebserv/response.cc
index 59dc51f..bedc10c 100644
--- a/libwebserv/response.cc
+++ b/libwebserv/response.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <libwebserv/response.h>
+#include <libwebserv/response_impl.h>
#include <algorithm>
@@ -27,30 +27,31 @@
namespace libwebserv {
-Response::Response(ProtocolHandler* handler, const std::string& request_id)
+ResponseImpl::ResponseImpl(ProtocolHandler* handler,
+ const std::string& request_id)
: handler_{handler}, request_id_{request_id} {
}
-Response::~Response() {
+ResponseImpl::~ResponseImpl() {
if (!reply_sent_) {
ReplyWithError(brillo::http::status_code::InternalServerError,
"Internal server error");
}
}
-void Response::AddHeader(const std::string& header_name,
- const std::string& value) {
+void ResponseImpl::AddHeader(const std::string& header_name,
+ const std::string& value) {
headers_.emplace(header_name, value);
}
-void Response::AddHeaders(
+void ResponseImpl::AddHeaders(
const std::vector<std::pair<std::string, std::string>>& headers) {
headers_.insert(headers.begin(), headers.end());
}
-void Response::Reply(int status_code,
- brillo::StreamPtr data_stream,
- const std::string& mime_type) {
+void ResponseImpl::Reply(int status_code,
+ brillo::StreamPtr data_stream,
+ const std::string& mime_type) {
CHECK(data_stream);
status_code_ = status_code;
data_stream_ = std::move(data_stream);
@@ -58,14 +59,14 @@
SendResponse();
}
-void Response::ReplyWithText(int status_code,
- const std::string& text,
- const std::string& mime_type) {
+void ResponseImpl::ReplyWithText(int status_code,
+ const std::string& text,
+ const std::string& mime_type) {
Reply(status_code, brillo::MemoryStream::OpenCopyOf(text, nullptr),
mime_type);
}
-void Response::ReplyWithJson(int status_code, const base::Value* json) {
+void ResponseImpl::ReplyWithJson(int status_code, const base::Value* json) {
std::string text;
base::JSONWriter::WriteWithOptions(
*json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &text);
@@ -76,8 +77,8 @@
ReplyWithText(status_code, text, mime_type);
}
-void Response::ReplyWithJson(int status_code,
- const std::map<std::string, std::string>& json) {
+void ResponseImpl::ReplyWithJson(
+ int status_code, const std::map<std::string, std::string>& json) {
base::DictionaryValue json_value;
for (const auto& pair : json) {
json_value.SetString(pair.first, pair.second);
@@ -85,22 +86,23 @@
ReplyWithJson(status_code, &json_value);
}
-void Response::Redirect(int status_code, const std::string& redirect_url) {
+void ResponseImpl::Redirect(int status_code, const std::string& redirect_url) {
AddHeader(brillo::http::response_header::kLocation, redirect_url);
ReplyWithError(status_code, "");
}
-void Response::ReplyWithError(int status_code, const std::string& error_text) {
+void ResponseImpl::ReplyWithError(int status_code,
+ const std::string& error_text) {
status_code_ = status_code;
data_stream_ = brillo::MemoryStream::OpenCopyOf(error_text, nullptr);
SendResponse();
}
-void Response::ReplyWithErrorNotFound() {
+void ResponseImpl::ReplyWithErrorNotFound() {
ReplyWithError(brillo::http::status_code::NotFound, "Not Found");
}
-void Response::SendResponse() {
+void ResponseImpl::SendResponse() {
CHECK(!reply_sent_) << "Response already sent";
reply_sent_ = true;
handler_->CompleteRequest(request_id_, status_code_, headers_,
diff --git a/libwebserv/response.h b/libwebserv/response.h
index fdd9cad..70e4f47 100644
--- a/libwebserv/response.h
+++ b/libwebserv/response.h
@@ -35,63 +35,48 @@
// Response class is a proxy for HTTP response used by the request handler
// to provide response HTTP headers and data.
-class LIBWEBSERV_EXPORT Response final {
+class LIBWEBSERV_EXPORT Response {
public:
- ~Response();
+ virtual ~Response() = default;
// Adds a single HTTP response header to the response.
- void AddHeader(const std::string& header_name, const std::string& value);
+ virtual void AddHeader(const std::string& header_name,
+ const std::string& value) = 0;
// Adds number of HTTP response headers to the response.
- void AddHeaders(
- const std::vector<std::pair<std::string, std::string>>& headers);
+ virtual void AddHeaders(
+ const std::vector<std::pair<std::string, std::string>>& headers) = 0;
// Generic reply method for sending arbitrary binary data response.
- void Reply(int status_code,
- brillo::StreamPtr data_stream,
- const std::string& mime_type);
+ virtual void Reply(int status_code,
+ brillo::StreamPtr data_stream,
+ const std::string& mime_type) = 0;
// Reply with text body.
- void ReplyWithText(int status_code,
- const std::string& text,
- const std::string& mime_type);
+ virtual void ReplyWithText(int status_code,
+ const std::string& text,
+ const std::string& mime_type) = 0;
// Reply with JSON object. The content type will be "application/json".
- void ReplyWithJson(int status_code, const base::Value* json);
+ virtual void ReplyWithJson(int status_code, const base::Value* json) = 0;
// Special form for JSON response for simple objects that have a flat
// list of key-value pairs of string type.
- void ReplyWithJson(int status_code,
- const std::map<std::string, std::string>& json);
+ virtual void ReplyWithJson(
+ int status_code, const std::map<std::string, std::string>& json) = 0;
// Issue a redirect response, so the client browser loads a page at
// the URL specified in |redirect_url|. If this is not an external URL,
// it must be an absolute path starting at the root "/...".
- void Redirect(int status_code, const std::string& redirect_url);
+ virtual void Redirect(int status_code, const std::string& redirect_url) = 0;
// Send a plain text response (with no Content-Type header).
// Usually used with error responses. |error_text| must be plain text.
- void ReplyWithError(int status_code, const std::string& error_text);
+ virtual void ReplyWithError(int status_code,
+ const std::string& error_text) = 0;
// Send "404 Not Found" response.
- void ReplyWithErrorNotFound();
-
- private:
- friend class ProtocolHandler;
-
- LIBWEBSERV_PRIVATE Response(ProtocolHandler* handler,
- const std::string& request_id);
-
- LIBWEBSERV_PRIVATE void SendResponse();
-
- ProtocolHandler* handler_{nullptr};
- std::string request_id_;
- int status_code_{0};
- brillo::StreamPtr data_stream_;
- std::multimap<std::string, std::string> headers_;
- bool reply_sent_{false};
-
- DISALLOW_COPY_AND_ASSIGN(Response);
+ virtual void ReplyWithErrorNotFound() = 0;
};
} // namespace libwebserv
diff --git a/libwebserv/response_impl.h b/libwebserv/response_impl.h
new file mode 100644
index 0000000..81b4faa
--- /dev/null
+++ b/libwebserv/response_impl.h
@@ -0,0 +1,71 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef WEBSERVER_LIBWEBSERV_RESPONSE_IMPL_H_
+#define WEBSERVER_LIBWEBSERV_RESPONSE_IMPL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <brillo/streams/stream.h>
+#include <libwebserv/response.h>
+
+namespace libwebserv {
+
+// Implementation of the Response interface.
+class ResponseImpl final : public Response {
+ public:
+ ~ResponseImpl() override;
+
+ // Overrides from Response.
+ void AddHeader(const std::string& header_name,
+ const std::string& value) override;
+ void AddHeaders(
+ const std::vector<std::pair<std::string, std::string>>& headers) override;
+ void Reply(int status_code,
+ brillo::StreamPtr data_stream,
+ const std::string& mime_type) override;
+ void ReplyWithText(int status_code,
+ const std::string& text,
+ const std::string& mime_type) override;
+ void ReplyWithJson(int status_code, const base::Value* json) override;
+ void ReplyWithJson(int status_code,
+ const std::map<std::string, std::string>& json) override;
+ void Redirect(int status_code, const std::string& redirect_url) override;
+ void ReplyWithError(int status_code, const std::string& error_text) override;
+ void ReplyWithErrorNotFound() override;
+
+ private:
+ friend class ProtocolHandler;
+
+ LIBWEBSERV_PRIVATE ResponseImpl(ProtocolHandler* handler,
+ const std::string& request_id);
+
+ LIBWEBSERV_PRIVATE void SendResponse();
+
+ ProtocolHandler* handler_{nullptr};
+ std::string request_id_;
+ int status_code_{0};
+ brillo::StreamPtr data_stream_;
+ std::multimap<std::string, std::string> headers_;
+ bool reply_sent_{false};
+
+ DISALLOW_COPY_AND_ASSIGN(ResponseImpl);
+};
+
+} // namespace libwebserv
+
+#endif // WEBSERVER_LIBWEBSERV_RESPONSE_IMPL_H_
diff --git a/libwebserv/server.cc b/libwebserv/server.cc
index 080fe03..7ca3c55 100644
--- a/libwebserv/server.cc
+++ b/libwebserv/server.cc
@@ -18,7 +18,7 @@
#include <vector>
#include <libwebserv/protocol_handler.h>
-#include <libwebserv/request.h>
+#include <libwebserv/request_impl.h>
#include "dbus_bindings/org.chromium.WebServer.RequestHandler.h"
#include "webservd/dbus-proxies.h"
@@ -68,7 +68,8 @@
protocol_handler_id.c_str());
return false;
}
- std::unique_ptr<Request> request{new Request{protocol_handler, url, method}};
+ std::unique_ptr<RequestImpl> request{
+ new RequestImpl{protocol_handler, url, method}};
// Convert request data into format required by the Request object.
for (const auto& tuple : in_params) {
if (std::get<0>(tuple))