: Google

, . , . , .

-, URL- Google Google-. HTML ULR- HTTP GET Google :

GET /addurl?url=http://www.foo.com&comment=Foo+comment HTTP/1.1

- : AddUrlFrontend, HTTP, , AddUrlService. AddUrlFrontend, , , , , , Google Bigtable[22] Google File System.[23]

:

$ mkdir depot/addurl/

AddUrlService Protocol Buffers:[24]

File: depot/addurl/addurl.proto

messageAddUrlRequest {

required string url = 1; // The URL address entered by user.

optional string comment = 2; // Comments made by user.

}

message AddUrlReply {

// Error code if an error occured.

optional int32 error_code = 1;

// Error mtssage if an error occured.

optional string error_details = 2;

}

service AddUrlService {

// Accepts a URL for submission to the index.

rpc AddUrl(AddUrlRequest) returns (AddUrlReply) {

option deadline = 10.0;

}

}

addurl.proto : AddUrlRequest AddUrlReply (RPC, Remote Procedure) AddUrlService.

AddUrlRequest, , url , comment .

AddUrlReply , error_code error_details . , , URL- , , . Google: .

AddUrlService , AddUrl, AddUrlRequest AddUrlReply. AddUrl - 10 , . AddUrlService , , addurl.proto.

'= 1' . , . , - uri AddUrlRequest . :

message AddUrlRequest {

required string url = 1; // The URL entered by the user.

optional string comment = 2; // Comments made by the user.

optional string uri = 3; // The URI entered by the user.

}

, url uri. , :

message AddUrlRequest {

required string uri = 1; // The URI entered by user.

optional string comment = 2; // Comments made by the user.

}

addurl.proto, proto_library, C++, addurl.proto, addurl C++. Java Python.

File: depot/addurl/BUILD

proto_library(name="addurl",

srcs=["addurl.proto"])

, addurl.proto BUILD. Protocol Buffers, addurl.pb.h addurl.pb.cc addurl, .

AddUrlFrontend. AddUrlFrontend addurl_frontend.h. .

File: depot/addurl/addurl_frontend.h

#ifndef ADDURL_ADDURL_FRONTEND_H_

#define ADDURL_ADDURL_FRONTEND_H_

// Forward-declaration of dependencies.

class AddUrlService;

class HTTPRequest;

class HTTPReply;

// Frontend for the AddUrl system.

// Accepts HTTP requests from web clients,

// and forwards well-formed requests to the backend.

class AddUrlFrontend {

public:

// Constructor which enables injection of an

// AddUrlService dependency.

explicit AddUrlFrontend(AddUrlService* add_url_service);

~AddUrlFrontend();

// Method invoked by our HTTP server when a request arrives

// for the /addurl resource.

void HandleAddUrlFrontendRequest(const HTTPRequest* http_request,

HTTPReply* http_reply);

private:

AddUrlService* add_url_service_;

// Declare copy constructor and operator= private to prohibit

// unintentional copying of instances of this class.

AddUrlFrontend(const AddUrlFrontend&);

AddUrlFrontend& operator=(const AddUrlFrontend& rhs);

};

#endif // ADDURL_ADDURL_FRONTEND_H_

AddUrlFrontend, addurl_frontend.cc, AddUrlFrontend. .

File: depot/addurl/addurl_frontend.cc

#include "addurl/addurl_frontend.h"

#include "addurl/addurl.pb.h"

#include "path/to/httpqueryparams.h"

// Functions used by HandleAddUrlFrontendRequest() below, but

// whose definitions are omitted for brevity.

void ExtractHttpQueryParams(const HTTPRequest* http_request,

HTTPQueryParams* query_params);

void WriteHttp200Reply(HTTPReply* reply);

void WriteHttpReplyWithErrorDetails(

HTTPReply* http_reply, const AddUrlReply& add_url_reply);

// AddUrlFrontend constructor that injects the AddUrlService

// dependency.

AddUrlFrontend::AddUrlFrontend(AddUrlService* add_url_service)

: add_url_service_(add_url_service) {

}

// AddUrlFrontend destructorthere'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_requestThe raw HTTP request received by the server.

// http_replyThe 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.1rnrn");

// 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.1rnrn");

// 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. , -.

, FakeAddUrlService (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"],

deps=[

"path/to/httpqueryparams",

"other_http_server_stuff",

":addurl", # Depends on the proto_library above.

])

# New:

cc_test(name="addurl_frontend_test",

size="small", # See section on Test Sizes.

srcs=["addurl_frontend_test.cc"],

deps=[

":addurl_frontend", # Depends on library above.

"path/to/googletest_main"])

addurl_frontend_test, . , , , AddUrlFrontend . FixtureTest . , , , , . ( , AddUrlService), .

$ create_cl BUILD

addurl.proto

addurl_frontend.h

addurl_frontend.cc

addurl_frontend_test.cc

$ mail_cl -m reviewer@google.com

, , , . Google , , , addurl_frontend_test , . , addurl_frontend.cc, addurl_frontend_test .


: 0.329. /Cache: 3 / 1