Skip to content

Commit

Permalink
Merge 87f93a1 into 6b4ec6e
Browse files Browse the repository at this point in the history
  • Loading branch information
gjasny committed Dec 16, 2020
2 parents 6b4ec6e + 87f93a1 commit cbf0631
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 4 deletions.
12 changes: 9 additions & 3 deletions pull/src/endpoint.cc
Expand Up @@ -19,7 +19,10 @@ Endpoint::Endpoint(CivetServer& server, std::string uri)

Endpoint::~Endpoint() {
server_.removeHandler(uri_);
server_.removeAuthHandler(uri_);
if (auth_handler_) {
// work-around https://github.com/civetweb/civetweb/issues/941
server_.removeAuthHandler(uri_);
}
}

void Endpoint::RegisterCollectable(
Expand All @@ -30,9 +33,12 @@ void Endpoint::RegisterCollectable(
void Endpoint::RegisterAuth(
std::function<bool(const std::string&, const std::string&)> authCB,
const std::string& realm) {
auth_handler_ =
// split creating, assigning, and storing to avoid a race-condition when
// being called the second time and the handler is replaced
auto new_handler =
detail::make_unique<BasicAuthHandler>(std::move(authCB), realm);
server_.addAuthHandler(uri_, auth_handler_.get());
server_.addAuthHandler(uri_, new_handler.get());
auth_handler_ = std::move(new_handler);
}

const std::string& Endpoint::GetURI() const { return uri_; }
Expand Down
2 changes: 1 addition & 1 deletion pull/src/handler.cc
Expand Up @@ -146,7 +146,7 @@ bool MetricsHandler::handleGet(CivetServer*, struct mg_connection* conn) {
}

void MetricsHandler::CleanupStalePointers(
std::vector<std::weak_ptr<Collectable>>& collectables) {
std::vector<std::weak_ptr<Collectable>>& collectables) {
collectables.erase(
std::remove_if(std::begin(collectables), std::end(collectables),
[](const std::weak_ptr<Collectable>& candidate) {
Expand Down
12 changes: 12 additions & 0 deletions pull/tests/integration/BUILD.bazel
Expand Up @@ -36,3 +36,15 @@ sh_test(
],
tags = ["manual"],
)

cc_test(
name = "integration_test",
srcs = ["integration_test.cc"],
copts = ["-Iexternal/googletest/include"],
linkstatic = True,
deps = [
"//pull",
"@com_github_curl//:curl",
"@com_google_googletest//:gtest_main",
],
)
20 changes: 20 additions & 0 deletions pull/tests/integration/CMakeLists.txt
Expand Up @@ -25,3 +25,23 @@ target_link_libraries(sample_server_auth
PRIVATE
${PROJECT_NAME}::pull
)

find_package(CURL)

if(CURL_FOUND)
add_executable(prometheus_pull_integration_test
integration_test.cc
)

target_link_libraries(prometheus_pull_integration_test
PRIVATE
${PROJECT_NAME}::pull
CURL::libcurl
GTest::gmock_main
)

add_test(
NAME prometheus_pull_integration_test
COMMAND prometheus_pull_integration_test
)
endif()
126 changes: 126 additions & 0 deletions pull/tests/integration/integration_test.cc
@@ -0,0 +1,126 @@
#include <curl/curl.h>
#include <gmock/gmock.h>

#include <memory>
#include <string>

#include "prometheus/counter.h"
#include "prometheus/detail/future_std.h"
#include "prometheus/exposer.h"
#include "prometheus/registry.h"

namespace prometheus {
namespace {

using namespace testing;

class IntegrationTest : public testing::Test {
public:
void SetUp() override {
exposer_ = detail::make_unique<Exposer>("127.0.0.1:0");
auto ports = exposer_->GetListeningPorts();
base_url_ = std::string("http://127.0.0.1:") + std::to_string(ports.at(0));
}

struct Resonse {
long code = 0;
std::string body;
};

Resonse FetchMetrics(std::string metrics_path) {
auto curl = std::shared_ptr<CURL>(curl_easy_init(), curl_easy_cleanup);
if (!curl) {
throw std::runtime_error("failed to initialize libcurl");
}

const auto url = base_url_ + metrics_path;
Resonse response;

curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response.body);
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback);

CURLcode curl_error = curl_easy_perform(curl.get());
if (curl_error != CURLE_OK) {
throw std::runtime_error("failed to perform HTTP request");
}

curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &response.code);

return response;
}

std::shared_ptr<Registry> RegisterSomeCounter(const std::string& name,
const std::string& path) {
const auto registry = std::make_shared<Registry>();

BuildCounter().Name(name).Register(*registry).Add({}).Increment();

exposer_->RegisterCollectable(registry, path);

return registry;
};

std::unique_ptr<Exposer> exposer_;

std::string base_url_;
std::string default_metrics_path_ = "/metrics";

private:
static size_t WriteCallback(void* contents, size_t size, size_t nmemb,
void* userp) {
auto response = reinterpret_cast<std::string*>(userp);

size_t realsize = size * nmemb;
response->append(reinterpret_cast<const char*>(contents), realsize);
return realsize;
}
};

TEST_F(IntegrationTest, doesNotExposeAnythingOnDefaultPath) {
const auto metrics = FetchMetrics(default_metrics_path_);

EXPECT_GE(metrics.code, 400);
}

TEST_F(IntegrationTest, exposeSingleCounter) {
const std::string counter_name = "example_total";
auto registry = RegisterSomeCounter(counter_name, default_metrics_path_);

const auto metrics = FetchMetrics(default_metrics_path_);

ASSERT_EQ(metrics.code, 200);
EXPECT_THAT(metrics.body, HasSubstr(counter_name));
}

TEST_F(IntegrationTest, exposesCountersOnDifferentUrls) {
const std::string first_metrics_path = "/first";
const std::string second_metrics_path = "/second";

const std::string first_counter_name = "first_total";
const std::string second_counter_name = "second_total";

const auto first_registry =
RegisterSomeCounter(first_counter_name, first_metrics_path);
const auto second_registry =
RegisterSomeCounter(second_counter_name, second_metrics_path);

// all set-up

const auto first_metrics = FetchMetrics(first_metrics_path);
const auto second_metrics = FetchMetrics(second_metrics_path);

// check results

ASSERT_EQ(first_metrics.code, 200);
ASSERT_EQ(second_metrics.code, 200);

EXPECT_THAT(first_metrics.body, HasSubstr(first_counter_name));
EXPECT_THAT(second_metrics.body, HasSubstr(second_counter_name));

EXPECT_THAT(first_metrics.body, Not(HasSubstr(second_counter_name)));
EXPECT_THAT(second_metrics.body, Not(HasSubstr(first_counter_name)));
}

} // namespace
} // namespace prometheus

0 comments on commit cbf0631

Please sign in to comment.