Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test push functionality #16

Merged
merged 4 commits into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ prometheus-client = { version = "0.22", default-features = false, optional = tru
reqwest = { version = "0.12", default-features = false, optional = true }
log = { version = "0.4", default-features = false, optional = true }

[dev-dependencies]
tokio = { version = "1.0", features = ["full"] }
mockito = "1.4"

[features]
default = ["non_blocking"]
non_blocking = []
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ use url::Url;
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let push_gateway: Url = Url::parse("<address to pushgateway>")?;
let client = Client::new();
let metrics_pusher = PrometheusClientMetricsPusher::from(client, &push_gateway)?;
let metrics_pusher = PrometheusClientMetricsPusher::create(client, &push_gateway)?;
let grouping: HashMap<&str, &str> = HashMap::from([("<label_name>", "<label_value>")]);
let mut metrics = String::new();
encode(&mut metrics, &registry)?;
Expand Down Expand Up @@ -139,7 +139,7 @@ use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let push_gateway: Url = Url::parse("<address to pushgateway>")?;
let client = Client::new();
let metrics_pusher = PrometheusClientMetricsPusherBlocking::from(client, &push_gateway)?;
let metrics_pusher = PrometheusClientMetricsPusherBlocking::create(client, &push_gateway)?;
let grouping: HashMap<&str, &str> = HashMap::from([("<label_name>", "<label_value>")]);
let mut metrics = String::new();
encode(&mut metrics, &registry)?;
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let push_gateway: Url = Url::parse("<address to pushgateway>")?;
//! let client = Client::new();
//! let metrics_pusher = PrometheusClientMetricsPusher::from(client, &push_gateway)?;
//! let metrics_pusher = PrometheusClientMetricsPusher::create(client, &push_gateway)?;
//! let grouping: HashMap<&str, &str> = HashMap::from([("<label_name>", "<label_value>")]);
//! let mut metrics = String::new();
//! encode(&mut metrics, &registry)?;
Expand Down Expand Up @@ -139,7 +139,7 @@
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let push_gateway: Url = Url::parse("<address to pushgateway>")?;
//! let client = Client::new();
//! let metrics_pusher = PrometheusClientMetricsPusherBlocking::from(client, &push_gateway)?;
//! let metrics_pusher = PrometheusClientMetricsPusherBlocking::create(client, &push_gateway)?;
//! let grouping: HashMap<&str, &str> = HashMap::from([("<label_name>", "<label_value>")]);
//! let mut metrics = String::new();
//! encode(&mut metrics, &registry)?;
Expand Down
131 changes: 131 additions & 0 deletions src/prometheus_client_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,134 @@ where
)
}
}

#[cfg(test)]
mod test {
use std::collections::HashMap;

use mockito::Mock;
use mockito::Server;
use mockito::ServerGuard;
use prometheus_client::encoding::text::encode;
use prometheus_client::encoding::EncodeLabelSet;
use prometheus_client::encoding::EncodeLabelValue;
use prometheus_client::metrics::counter::Counter;
use prometheus_client::metrics::family::Family;
use prometheus_client::registry::Registry;
use prometheus_client_crate::PrometheusClientMetricsPusher;
use prometheus_client_crate::PrometheusClientMetricsPusherBlocking;
use url::Url;

use crate::prometheus_client_crate;

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelValue)]
enum Method {
#[allow(clippy::upper_case_acronyms)]
GET,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)]
struct Labels {
// Use your own enum types to represent label values.
method: Method,
// Or just a plain string.
path: String,
}

fn create_metrics() -> String {
// Given I have a counter metric
let mut registry = <Registry>::default();
let http_requests = Family::<Labels, Counter>::default();
registry.register(
"http_requests",
"Number of HTTP requests received",
http_requests.clone(),
);
http_requests
.get_or_create(&Labels { method: Method::GET, path: "/metrics".to_string() })
.inc();

let mut metrics = String::new();
encode(&mut metrics, &registry).unwrap();

metrics
}

fn create_push_gateway_mock(
server: &mut ServerGuard,
) -> (Mock, Url, &'static str, HashMap<&'static str, &'static str>) {
let pushgateway_address = Url::parse(&server.url()).unwrap();
let job = "prometheus_client_crate_job";
let label_name = "kind";
let label_value = "test";
let path = format!("/metrics/job/{job}/{label_name}/{label_value}");

let grouping: HashMap<&str, &str> = HashMap::from([(label_name, label_value)]);

let expected = "# HELP http_requests Number of HTTP requests received.\n".to_owned()
+ "# TYPE http_requests counter\n"
+ "http_requests_total{method=\"GET\",path=\"/metrics\"} 1\n"
+ "# EOF\n";

let pushgateway_mock = server
.mock("PUT", &*path)
.with_status(200)
.match_header("content-type", "text/plain")
.match_body(mockito::Matcher::from(&*expected))
.create();

(pushgateway_mock, pushgateway_address, job, grouping)
}

#[cfg(feature = "with_reqwest_blocking")]
#[test]
fn test_push_all_blocking_reqwest_prometheus_client_crate() {
use reqwest::blocking::Client;
// Given I have a counter metric
let metrics = create_metrics();

// And a push gateway and a job
let mut server = Server::new();
let (pushgateway_mock, push_gateway_address, job, grouping) =
create_push_gateway_mock(&mut server);

// And a blocking prometheus metrics pusher
let metrics_pusher =
PrometheusClientMetricsPusherBlocking::create(Client::new(), &push_gateway_address)
.unwrap();

// When I push all metrics to the push gateway
metrics_pusher
.push_all(job, &grouping, metrics)
.expect("Failed to push metrics");

// Then the metrics are received by the push_gateway
pushgateway_mock.expect(1).assert();
}

#[cfg(feature = "with_reqwest")]
#[tokio::test]
async fn test_push_all_non_blocking_reqwest_prometheus_client_crate() {
use reqwest::Client;
// Given I have a counter metric
let metrics = create_metrics();

// And a push gateway and a job
let mut server = Server::new_async().await;
let (pushgateway_mock, push_gateway_address, job, grouping) =
create_push_gateway_mock(&mut server);

// And a nonblocking prometheus metrics pusher
let metrics_pusher =
PrometheusClientMetricsPusher::create(Client::new(), &push_gateway_address).unwrap();

// When I push all metrics to the push gateway
metrics_pusher
.push_all(job, &grouping, metrics)
.await
.expect("Failed to push metrics");

// Then the metrics are received by the push_gateway
pushgateway_mock.expect(1).assert();
}
}
107 changes: 107 additions & 0 deletions src/prometheus_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,110 @@ where
)
}
}

#[cfg(test)]
mod test {
use std::collections::HashMap;

use mockito::Mock;
use mockito::Server;
use mockito::ServerGuard;
use prometheus::labels;
use prometheus::proto::MetricFamily;
use prometheus::Counter;
use prometheus::Encoder;
use prometheus::Opts;
use prometheus::ProtobufEncoder;
use prometheus_crate::PrometheusMetricsPusher;
use prometheus_crate::PrometheusMetricsPusherBlocking;
use url::Url;

use crate::prometheus_crate;

fn create_metrics(name: &str) -> (Vec<u8>, Vec<MetricFamily>) {
let counter_opts = Opts::new(name, "test counter help");
let counter = Counter::with_opts(counter_opts).unwrap();
prometheus::register(Box::new(counter.clone())).unwrap();
counter.inc();

let encoder = ProtobufEncoder::new();
let metric_families = prometheus::gather();
let mut metrics = vec![];
encoder.encode(&metric_families, &mut metrics).unwrap();

(metrics, metric_families)
}

fn create_push_gateway_mock(
server: &mut ServerGuard,
metrics: Vec<u8>,
) -> (Mock, Url, &str, HashMap<&str, &str>) {
let push_gateway_address = Url::parse(&server.url()).unwrap();
let job = "prometheus_crate_job";
let label_name = "kind";
let label_value = "test";
let path = format!("/metrics/job/{job}/{label_name}/{label_value}");
let grouping = labels! { label_name => label_value };

let pushgateway_mock = server
.mock("PUT", &*path)
.with_status(200)
.match_header("content-type", ProtobufEncoder::new().format_type())
.match_body(mockito::Matcher::from(metrics))
.create();

(pushgateway_mock, push_gateway_address, job, grouping)
}

#[cfg(feature = "with_reqwest_blocking")]
#[test]
fn test_push_all_blocking_reqwest_prometheus_crate() {
// Given I have a counter metric
let (metrics, metric_families) = create_metrics("test_counter");

// And a push gateway and a job
let mut server = Server::new();
let (pushgateway_mock, push_gateway_address, job, grouping) =
create_push_gateway_mock(&mut server, metrics);

// And a blocking prometheus metrics pusher
let metrics_pusher = PrometheusMetricsPusherBlocking::from(
reqwest::blocking::Client::new(),
&push_gateway_address,
)
.unwrap();

// When I push all metrics to the push gateway
metrics_pusher
.push_all(job, &grouping, metric_families)
.expect("Failed to push metrics");

// Then the metrics are received by the push_gateway
pushgateway_mock.expect(1).assert();
}

#[cfg(feature = "with_reqwest")]
#[tokio::test]
async fn test_push_all_non_blocking_reqwest_prometheus_crate() {
// Given I have a counter metric
let (metrics, metric_families) = create_metrics("test_counter_async");

// And a push gateway and a job
let mut server = Server::new_async().await;
let (pushgateway_mock, push_gateway_address, job, grouping) =
create_push_gateway_mock(&mut server, metrics);

// And a nonblocking prometheus metrics pusher
let metrics_pusher =
PrometheusMetricsPusher::from(reqwest::Client::new(), &push_gateway_address).unwrap();

// When I push all metrics to the push gateway
metrics_pusher
.push_all(job, &grouping, metric_families)
.await
.expect("Failed to push metrics");

// Then the metrics are received by the push_gateway
pushgateway_mock.expect(1).assert();
}
}
Loading