// dependency.
AddUrlFrontend::AddUrlFrontend(AddUrlService* add_url_service)
: add_url_service_(add_url_service) {
}
// AddUrlFrontend destructorβthere's nothing to do here.
AddUrlFrontend::~AddUrlFrontend() {
}
// HandleAddUrlFrontendRequest:
// Handles requests to /addurl by parsing the request,
// dispatching a backend request to an AddUrlService backend,
// and transforming the backend reply into an appropriate
// HTTP reply.
//
// Args:
// http_requestβThe raw HTTP request received by the server.
// http_replyβThe raw HTTP reply to send in response.
void AddUrlFrontend::HandleAddUrlFrontendRequest(
const HTTPRequest* http_request, HTTPReply* http_reply) {
// Extract the query parameters from the raw HTTP request.
HTTPQueryParams query_params;
ExtractHttpQueryParams(http_request, &query_params);
// Get the 'url' and 'comment' query components.
// Default each to an empty string if they were not present
// in http_request.
string url =
query_params.GetQueryComponentDefault("url", "");
string comment =
query_params.GetQueryComponentDefault("comment", "");
// Prepare the request to the AddUrlService backend.
AddUrlRequest add_url_request;
AddUrlReply add_url_reply;
add_url_request.set_url(url);
if (!comment.empty()) {
add_url_request.set_comment(comment);
}
// Issue the request to the AddUrlService backend.
RPC rpc;
add_url_service_->AddUrl(
&rpc, &add_url_request, &add_url_reply);
// Block until the reply is received from the
// AddUrlService backend.
rpc.Wait();
// Handle errors, if any:
if (add_url_reply.has_error_code()) {
WriteHttpReplyWithErrorDetails(http_reply, add_url_reply);
} else {
// No errors. Send HTTP 200 OK response to client.
WriteHttp200Reply(http_reply);
}
}
ΠΠ° ΡΡΠ½ΠΊΡΠΈΡ HandleAddUrlFrontendRequest Π»ΠΎΠΆΠΈΡΡΡ Π±ΠΎΠ»ΡΡΠ°Ρ Π½Π°Π³ΡΡΠ·ΠΊΠ° β ΡΠ°ΠΊ ΡΡΡΡΠΎΠ΅Π½Ρ ΠΌΠ½ΠΎΠ³ΠΈΠ΅ Π²Π΅Π±-ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ. Π Π°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΠΌΠΎΠΆΠ΅Ρ ΡΠ°Π·Π³ΡΡΠ·ΠΈΡΡ ΡΡΡ ΡΡΠ½ΠΊΡΠΈΡ, Π²ΡΠ΄Π΅Π»ΠΈΠ² ΡΠ°ΡΡΡ Π΅Π΅ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΠΈ Π²ΡΠΏΠΎΠΌΠΎΠ³Π°ΡΠ΅Π»ΡΠ½ΡΠΌ ΡΡΠ½ΠΊΡΠΈΡΠΌ. ΠΠΎ ΡΠ°ΠΊΠΎΠΉ ΡΠ΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³ ΠΎΠ±ΡΡΠ½ΠΎ Π½Π΅ ΠΏΡΠΎΠ²ΠΎΠ΄ΡΡ, ΠΏΠΎΠΊΠ° ΡΠ±ΠΎΡΠΊΠ° Π½Π΅ ΡΡΠ°Π½Π΅Ρ ΡΡΠ°Π±ΠΈΠ»ΡΠ½ΠΎΠΉ, Π° Π½Π°ΠΏΠΈΡΠ°Π½Π½ΡΠ΅ ΡΠ½ΠΈΡ-ΡΠ΅ΡΡΡ Π½Π΅ Π±ΡΠ΄ΡΡ ΡΡΠΏΠ΅ΡΠ½ΠΎ ΠΏΡΠΎΡ ΠΎΠ΄ΠΈΡΡ.
Π ΡΡΠΎΠΌ ΠΌΠ΅ΡΡΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅Ρ ΡΡΡΠ΅ΡΡΠ²ΡΡΡΡΡ ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ ΡΠ±ΠΎΡΠΊΠΈ ΠΏΡΠΎΠ΅ΠΊΡΠ° addurl, Π²ΠΊΠ»ΡΡΠ°Ρ Π² Π½Π΅Π΅ Π·Π°ΠΏΠΈΡΡ Π΄Π»Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ addurl_frontend. ΠΡΠΈ ΡΠ±ΠΎΡΠΊΠ΅ ΡΠΎΠ·Π΄Π°Π΅ΡΡΡ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° C++ Π΄Π»Ρ AddUrlFrontend.
File: /depot/addurl/BUILD
# From before:
proto_library(name="addurl",
srcs=["addurl.proto"])
# New:
cc_library(name="addurl_frontend",
srcs=["addurl_frontend.cc"],
deps=[
"path/to/httpqueryparams",
"other_http_server_stuff",
":addurl", # Link against the addurl library above.
])
Π Π°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΡΠ½ΠΎΠ²Π° Π·Π°ΠΏΡΡΠΊΠ°Π΅Ρ ΡΡΠ΅Π΄ΡΡΠ²Π° ΡΠ±ΠΎΡΠΊΠΈ, ΠΈΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ ΠΎΡΠΈΠ±ΠΊΠΈ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½ΠΎΠ²ΡΠΈΠΊΠ° Π² addurl_frontend.h ΠΈ addurl_frontend.cc, ΠΏΠΎΠΊΠ° Π²ΡΠ΅ Π½Π΅ Π±ΡΠ΄Π΅Ρ ΡΠΎΠ±ΠΈΡΠ°ΡΡΡΡ ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½ΠΎΠ²Π°ΡΡΡΡ Π±Π΅Π· ΠΏΡΠ΅Π΄ΡΠΏΡΠ΅ΠΆΠ΄Π΅Π½ΠΈΠΉ ΠΈΠ»ΠΈ ΠΎΡΠΈΠ±ΠΎΠΊ. ΠΠ° ΡΡΠΎΠΉ ΡΡΠ°Π΄ΠΈΠΈ ΠΏΠΎΡΠ° ΠΏΠΈΡΠ°ΡΡ ΡΠ½ΠΈΡ-ΡΠ΅ΡΡΡ Π΄Π»Ρ AddUrlFrontend. ΠΠ½ΠΈ ΠΏΠΈΡΡΡΡΡ Π² Π½ΠΎΠ²ΠΎΠΌ ΡΠ°ΠΉΠ»Π΅ addurl_frontend_test.cc. Π’Π΅ΡΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅Ρ ΠΈΠΌΠΈΡΠ°ΡΠΈΡ Π΄Π»Ρ Π±ΡΠΊΠ΅Π½Π΄-ΡΠΈΡΡΠ΅ΠΌΡ AddUrlService ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡ AddUrlFrontend Π΄Π»Ρ Π²Π½Π΅Π΄ΡΠ΅Π½ΠΈΡ ΡΡΠΎΠΉ ΠΈΠΌΠΈΡΠ°ΡΠΈΠΈ Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ. ΠΡΠΈ ΡΠ°ΠΊΠΎΠΌ ΠΏΠΎΠ΄Ρ ΠΎΠ΄Π΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΠΌΠΎΠΆΠ΅Ρ Π²Π½Π΅Π΄ΡΡΡΡ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ ΠΈ ΠΎΡΠΈΠ±ΠΊΠΈ Π² ΠΏΠΎΡΠΎΠΊ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ AddUrlFrontend Π±Π΅Π· ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΠΊΠΎΠ΄Π° AddUrlFrontend.
File: depot/addurl/addurl_frontend_test.cc
#include "addurl/addurl.pb.h"
#include "addurl/addurl_frontend.h"
// See http://code.google.com/p/googletest/
#include "path/to/googletest.h"
// Defines a fake AddUrlService, which will be injected by
// the AddUrlFrontendTest test fixture into AddUrlFrontend
// instances under test.
class FakeAddUrlService : public AddUrlService {
public:
FakeAddUrlService()
: has_request_expectations_(false),
error_code_(0) {
}
// Allows tests to set expectations on requests.
void set_expected_url(const string& url) {
expected_url_ = url;
has_request_expectations_ = true;
}
void set_expected_comment(const string& comment) {
expected_comment_ = comment;
has_request_expectations_ = true;
}
// Allows for injection of errors by tests.
void set_error_code(int error_code) {
error_code_ = error_code;
}
void set_error_details(const string& error_details) {
error_details_ = error_details;
}
// Overrides of the AddUrlService::AddUrl method generated from
// service definition in addurl.proto by the Protocol Buffer
// compiler.
virtual void AddUrl(RPC* rpc,
const AddUrlRequest* request,
AddUrlReply* reply) {
// Enforce expectations on request (if present).
if (has_request_expectations_) {
EXPECT_EQ(expected_url_, request->url());
EXPECT_EQ(expected_comment_, request->comment());
}
// Inject errors specified in the set_* methods above if present.
if (error_code_ != 0 || !error_details_.empty()) {
reply->set_error_code(error_code_);
reply->set_error_details(error_details_);
}
}
private:
// Expected request information.
// Clients set using set_expected_* methods.
string expected_url_;
string expected_comment_;
bool has_request_expectations_;
// Injected error information.
// Clients set using set_* methods above.
int error_code_;
string error_details_;
};
// The test fixture for AddUrlFrontend. It is code shared by the
// TEST_F test definitions below. For every test using this
// fixture, the fixture will create a FakeAddUrlService, an
// AddUrlFrontend, and inject the FakeAddUrlService into that
// AddUrlFrontend. Tests will have access to both of these
// objects at runtime.
class AddurlFrontendTest : public ::testing::Test {
// Runs before every test method is executed.
virtual void SetUp() {
// Create a FakeAddUrlService for injection.
fake_add_url_service_.reset(new FakeAddUrlService);
// Create an AddUrlFrontend and inject our FakeAddUrlService
// into it.
add_url_frontend_.reset(
new AddUrlFrontend(fake_add_url_service_.get()));
}
scoped_ptr<FakeAddUrlService> fake_add_url_service_;
scoped_ptr<AddUrlFrontend> add_url_frontend_;
};
// Test that AddurlFrontendTest::SetUp works.
TEST_F(AddurlFrontendTest, FixtureTest) {
// AddurlFrontendTest::SetUp was invoked by this point.
}
// Test that AddUrlFrontend parses URLs correctly from its
// query parameters.
TEST_F(AddurlFrontendTest, ParsesUrlCorrectly) {
HTTPRequest http_request;
HTTPReply http_reply;
// Configure the request to go to the /addurl resource and
// to contain a 'url' query parameter.
http_request.set_text(
"GET /addurl?url=http://www.foo.com HTTP/1.1\r\n\r\n");
// Tell the FakeAddUrlService to expect to receive a URL
// of 'http://www.foo.com'.
fake_add_url_service_->set_expected_url("http://www.foo.com");
// Send the request to AddUrlFrontend, which should dispatch
// a request to the FakeAddUrlService.
add_url_frontend_->HandleAddUrlFrontendRequest(
&http_request, &http_reply);
// Validate the response.
EXPECT_STREQ("200 OK", http_reply.text());
}
// Test that AddUrlFrontend parses comments correctly from its
// query parameters.
TEST_F(AddurlFrontendTest, ParsesCommentCorrectly) {
HTTPRequest http_request;
HTTPReply http_reply;
// Configure the request to go to the /addurl resource and
// to contain a 'url' query parameter and to also contain
// a 'comment' query parameter that contains the
// url-encoded query string 'Test comment'.
http_request.set_text("GET /addurl?url=http://www.foo.com"
"&comment=Test+comment HTTP/1.1\r\n\r\n");
// Tell the FakeAddUrlService to expect to receive a URL
// of 'http://www.foo.com' again.
fake_add_url_service_->set_expected_url("http://www.foo.com");
// Tell the FakeAddUrlService to also expect to receive a
// comment of 'Test comment' this time.
fake_add_url_service_->set_expected_comment("Test comment");
Π Π°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π½Π°ΠΏΠΈΡΠ΅Ρ Π΅ΡΠ΅ ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΡ ΠΎΠΆΠΈΡ ΡΠ΅ΡΡΠΎΠ², Π½ΠΎ ΡΡΠΎΡ ΠΏΡΠΈΠΌΠ΅Ρ Ρ ΠΎΡΠΎΡΠΎ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠΈΡΡΠ΅Ρ ΠΎΠ±ΡΡΡ ΡΡ Π΅ΠΌΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ ΠΈΠΌΠΈΡΠ°ΡΠΈΠΈ, Π΅Π΅ Π²Π½Π΅Π΄ΡΠ΅Π½ΠΈΡ Π² ΡΠ΅ΡΡΠΈΡΡΠ΅ΠΌΡΡ ΡΠΈΡΡΠ΅ΠΌΡ. ΠΠ½ ΠΎΠ±ΡΡΡΠ½ΡΠ΅Ρ, ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΈΠΌΠΈΡΠ°ΡΠΈΡ Π² ΡΠ΅ΡΡΠ°Ρ Π΄Π»Ρ Π²Π½Π΅Π΄ΡΠ΅Π½ΠΈΡ ΠΎΡΠΈΠ±ΠΎΠΊ ΠΈ Π»ΠΎΠ³ΠΈΠΊΠΈ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ Π² ΠΏΠΎΡΠΎΠΊΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ ΡΠ΅ΡΡΠΈΡΡΠ΅ΠΌΠΎΠΉ ΡΠΈΡΡΠ΅ΠΌΡ. ΠΠ΄ΠΈΠ½ ΠΈΠ· ΠΎΡΡΡΡΡΡΠ²ΡΡΡΠΈΡ Π·Π΄Π΅ΡΡ Π²Π°ΠΆΠ½ΡΡ ΡΠ΅ΡΡΠΎΠ² ΠΈΠΌΠΈΡΠΈΡΡΠ΅Ρ ΡΠ΅ΡΠ΅Π²ΠΎΠΉ ΡΠ°ΠΉΠΌ-Π°ΡΡ ΠΌΠ΅ΠΆΠ΄Ρ AddUrlFrontend ΠΈ Π±ΡΠΊΠ΅Π½Π΄-ΡΠΈΡΡΠ΅ΠΌΠΎΠΉ FakeAddUrlService. Π’Π°ΠΊΠΎΠΉ ΡΠ΅ΡΡ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ, Π΅ΡΠ»ΠΈ Π½Π°Ρ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π·Π°Π±ΡΠ» ΠΏΡΠΎΠ²Π΅ΡΠΈΡΡ ΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°ΡΡ ΡΠΈΡΡΠ°ΡΠΈΡ Ρ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠ΅ΠΌ ΡΠ°ΠΉΠΌ-Π°ΡΡΠ°.
ΠΠ½Π°ΡΠΎΠΊΠΈ Π³ΠΈΠ±ΠΊΠΎΠΉ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ»ΠΎΠ³ΠΈΠΈ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΡΠΊΠ°ΠΆΡΡ, ΡΡΠΎ Π²ΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ FakeAddΒUrlService Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΠΏΡΠΎΡΡΡ ΠΈ Π²ΠΌΠ΅ΡΡΠΎ ΠΈΠΌΠΈΡΠ°ΡΠΈΠΈ (fake) ΠΌΠΎΠΆΠ½ΠΎ Π±ΡΠ»ΠΎ Π±Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΏΠΎΠ΄ΡΡΠ°Π²Π½ΠΎΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ (mock). Π ΠΎΠ½ΠΈ Π±ΡΠ΄ΡΡ ΠΏΡΠ°Π²Ρ. ΠΡ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ ΡΡΠΈ ΡΡΠ½ΠΊΡΠΈΠΈ Π² Π²ΠΈΠ΄Π΅ ΠΈΠΌΠΈΡΠ°ΡΠΈΠΈ ΠΈΡΠΊΠ»ΡΡΠΈΡΠ΅Π»ΡΠ½ΠΎ Π΄Π»Ρ ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠ»Π΅Π½ΠΈΡ Ρ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠΌ.
Π’Π΅ΠΏΠ΅ΡΡ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ Ρ ΠΎΡΠ΅Ρ Π²ΡΠΏΠΎΠ»Π½ΠΈΡΡ Π½Π°ΠΏΠΈΡΠ°Π½Π½ΡΠ΅ ΡΠ΅ΡΡΡ. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΠΎΠ½ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΠ±Π½ΠΎΠ²ΠΈΡΡ ΡΠ²ΠΎΠΈ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ ΡΠ±ΠΎΡΠΊΠΈ ΠΈ Π²ΠΊΠ»ΡΡΠΈΡΡ Π½ΠΎΠ²ΠΎΠ΅ ΡΠ΅ΡΡΠΎΠ²ΠΎΠ΅ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ, ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΡΡΠ΅Π΅ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ ΡΠ΅ΡΡΠ° addurl_frontend_test.
File: depot/addurl/BUILD
# From before:
proto_library(name="addurl",
srcs=["addurl.proto"])
# Also from before:
cc_library(name="addurl_frontend",
srcs=["addurl_frontend.cc"],