-
Notifications
You must be signed in to change notification settings - Fork 11
Add unit tests for environment with fake HTTP server. #139
Changes from 6 commits
90bd2ce
b686734
3d7c1c4
ff6fe28
639adf7
2b5db18
a86a373
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,11 @@ class Environment { | |
|
||
void ReadApplicationDefaultCredentials() const; | ||
|
||
// The url must end in a '/'. | ||
void SetMetadataServerUrlForTest(const std::string& url) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this only "ForTest"? It seems like a reasonable enough setter function to remove that suffix. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to make it clear that the method only exists because we need to override the URL in test code. If we ever need to use it in production code, we can rename the method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SGTM |
||
metadata_server_url_ = url; | ||
} | ||
|
||
const Configuration& config_; | ||
|
||
// Cached data. | ||
|
@@ -60,6 +65,7 @@ class Environment { | |
mutable std::string kubernetes_cluster_location_; | ||
mutable std::string client_email_; | ||
mutable std::string private_key_; | ||
mutable std::string metadata_server_url_; | ||
mutable bool application_default_credentials_read_; | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
#include "../src/environment.h" | ||
#include "fake_http_server.h" | ||
#include "gtest/gtest.h" | ||
|
||
#include <fstream> | ||
|
@@ -12,9 +13,15 @@ class EnvironmentTest : public ::testing::Test { | |
static void ReadApplicationDefaultCredentials(const Environment& environment) { | ||
environment.ReadApplicationDefaultCredentials(); | ||
} | ||
|
||
static void SetMetadataServerUrlForTest(Environment* environment, | ||
const std::string& url) { | ||
environment->SetMetadataServerUrlForTest(url); | ||
} | ||
}; | ||
|
||
namespace { | ||
|
||
// A file with a given name in a temporary (unique) directory. | ||
boost::filesystem::path TempPath(const std::string& filename) { | ||
boost::filesystem::path path = boost::filesystem::temp_directory_path(); | ||
|
@@ -42,6 +49,7 @@ class TemporaryFile { | |
private: | ||
boost::filesystem::path path_; | ||
}; | ||
|
||
} // namespace | ||
|
||
TEST(TemporaryFile, Basic) { | ||
|
@@ -70,7 +78,6 @@ TEST_F(EnvironmentTest, ReadApplicationDefaultCredentialsSucceeds) { | |
TemporaryFile credentials_file( | ||
std::string(test_info_->name()) + "_creds.json", | ||
"{\"client_email\":\"[email protected]\",\"private_key\":\"some_key\"}"); | ||
std::string cfg; | ||
Configuration config(std::istringstream( | ||
"CredentialsFile: '" + credentials_file.FullPath().native() + "'\n" | ||
)); | ||
|
@@ -98,4 +105,17 @@ TEST_F(EnvironmentTest, ReadApplicationDefaultCredentialsCaches) { | |
); | ||
EXPECT_EQ("some_key", environment.CredentialsPrivateKey()); | ||
} | ||
|
||
TEST_F(EnvironmentTest, GetMetadataString) { | ||
testing::FakeServer server; | ||
server.SetResponse("/a/b/c", "hello"); | ||
|
||
Configuration config; | ||
Environment environment(config); | ||
SetMetadataServerUrlForTest(&environment, server.GetUrl()); | ||
|
||
EXPECT_EQ("hello", environment.GetMetadataString("a/b/c")); | ||
EXPECT_EQ("", environment.GetMetadataString("unknown/path")); | ||
} | ||
|
||
} // namespace google |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#include "fake_http_server.h" | ||
|
||
namespace google { | ||
namespace testing { | ||
|
||
// Note: An empty port selects a random available port (this behavior | ||
// is not documented). | ||
FakeServer::FakeServer() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about a comment along the lines of "an empty port selects a random available port (undocumented)"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't a class comment — let's move it to where the empty port is passed in. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
: server_(Server::options(handler_).address("127.0.0.1").port("")) { | ||
server_.listen(); | ||
server_thread_ = std::thread([this] { server_.run(); }); | ||
} | ||
|
||
FakeServer::~FakeServer() { | ||
server_.stop(); | ||
server_thread_.join(); | ||
} | ||
|
||
std::string FakeServer::GetUrl() { | ||
network::uri_builder builder; | ||
builder.scheme("http").host(server_.address()).port(server_.port()).path("/"); | ||
return builder.uri().string(); | ||
} | ||
|
||
void FakeServer::SetResponse(const std::string& path, | ||
const std::string& response) { | ||
handler_.path_responses[path] = response; | ||
} | ||
|
||
void FakeServer::Handler::operator()(Server::request const &request, | ||
Server::connection_ptr connection) { | ||
auto it = path_responses.find(request.destination); | ||
if (it != path_responses.end()) { | ||
connection->set_status(Server::connection::ok); | ||
connection->set_headers(std::map<std::string, std::string>({ | ||
{"Content-Type", "text/plain"}, | ||
})); | ||
connection->write(it->second); | ||
} else { | ||
// Note: We have to set headers; otherwise, an exception is thrown. | ||
connection->set_status(Server::connection::not_found); | ||
connection->set_headers(std::map<std::string, std::string>()); | ||
} | ||
} | ||
|
||
} // testing | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#ifndef FAKE_HTTP_SERVER_H_ | ||
#define FAKE_HTTP_SERVER_H_ | ||
|
||
#include <boost/network/protocol/http/server.hpp> | ||
|
||
namespace google { | ||
namespace testing { | ||
|
||
// Starts a server in a separate thread, allowing it to choose an | ||
// available port. | ||
class FakeServer { | ||
public: | ||
FakeServer(); | ||
~FakeServer(); | ||
|
||
std::string GetUrl(); | ||
void SetResponse(const std::string& path, const std::string& response); | ||
|
||
private: | ||
struct Handler; | ||
typedef boost::network::http::server<Handler> Server; | ||
|
||
// Handler that maps paths to response strings. | ||
struct Handler { | ||
void operator()(Server::request const &request, | ||
Server::connection_ptr connection); | ||
std::map<std::string, std::string> path_responses; | ||
}; | ||
|
||
Handler handler_; | ||
Server server_; | ||
std::thread server_thread_; | ||
}; | ||
|
||
} // testing | ||
|
||
#endif // FAKE_HTTP_SERVER_H_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could add a comment saying that the
url
must end in a'/'
...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.