Skip to content

Commit

Permalink
test: test log-level endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoe Spellman committed Mar 7, 2024
1 parent 4a2453e commit 732dbd4
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ tonic-build = { version = "0.11", features = ["prost"] }

[dev-dependencies]
cucumber = { version = "0.20.2", features = ["libtest", "tracing"] }
serde_json = "1.0.114"


[[test]]
Expand All @@ -63,3 +64,7 @@ harness = false
[[test]]
name = "chart"
harness = false

[[test]]
name = "log_level"
harness = false
5 changes: 3 additions & 2 deletions src/features/admin/log_level/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use log::Level;
use serde::{Deserialize, Serialize};

/// The request for setting the log level
#[derive(Copy, Clone, Deserialize)]
#[derive(Copy, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SetLogLevelRequest {
/// The current log level, [`tracing`] doesn't implement [`serde`] traits so
// we convert between the two internally.
Expand All @@ -16,7 +17,7 @@ pub struct SetLogLevelRequest {
pub struct SetLogLevelResponse;

/// Returns the log level to the caller
#[derive(Copy, Clone, Serialize)]
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct GetLogLevelResponse {
/// The current log level, [`tracing`] doesn't implement [`serde`] traits so
// we convert between the two internally.
Expand Down
19 changes: 19 additions & 0 deletions tests/features/admin/log-level.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: Can retrieve and set the internal log level via the REST endpoint

Scenario: Espio wants to find out the current log level
Given Espio doesn't know the log level
When Espio asks for the log level
Then Espio gets an answer

Scenario Outline: Espio wants to set the log level
Given the service's current log level
When Espio requests it changes to <level>
Then the log level is set to <level>

Examples:
| level |
| error |
| info |
| debug |
| warn |
| trace |
45 changes: 45 additions & 0 deletions tests/helpers/client/log_level.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::str::FromStr;

use axum::async_trait;
use log::Level;
use ratings::features::admin::log_level::interface::{GetLogLevelResponse, SetLogLevelRequest};
use reqwest::Url;

use super::Client;

#[async_trait]
pub trait LogClient: Client {
fn rest_url(&self) -> Url {
Url::from_str(self.url())
.unwrap()
.join("/v1/admin/log-level")
.unwrap()
}

async fn get_log_level(
&self,
) -> Result<GetLogLevelResponse, Box<dyn std::error::Error + Send + Sync>> {
Ok(serde_json::from_str(
&reqwest::get(self.rest_url())
.await?
.error_for_status()?
.text()
.await?,
)?)
}

async fn set_log_level(
&self,
level: Level,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
reqwest::Client::new()
.post(self.rest_url())
.header("Content-Type", "application/json")
.body(serde_json::to_string(&SetLogLevelRequest { level }).unwrap())
.send()
.await?
.error_for_status_ref()?;

Ok(())
}
}
4 changes: 3 additions & 1 deletion tests/helpers/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
pub mod app;
pub mod chart;
pub mod log_level;
pub mod user;

use std::fmt::Display;

pub use self::{app::AppClient, chart::ChartClient, user::UserClient};
pub use self::{app::AppClient, chart::ChartClient, log_level::LogClient, user::UserClient};

pub trait Client {
fn url(&self) -> &str;
Expand Down Expand Up @@ -33,3 +34,4 @@ impl Client for TestClient {
impl AppClient for TestClient {}
impl ChartClient for TestClient {}
impl UserClient for TestClient {}
impl LogClient for TestClient {}
1 change: 1 addition & 0 deletions tests/helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(dead_code)]
#![cfg(test)]

pub mod assert;
pub mod client;
Expand Down
110 changes: 110 additions & 0 deletions tests/log_level.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use std::str::FromStr;

use cucumber::{given, then, when, Parameter, World};

use helpers::client::*;
use ratings::utils::Config;

mod helpers;

#[derive(Copy, Clone, Eq, PartialEq, Parameter, Debug)]
#[param(name = "level", regex = "info|warn|debug|trace|error")]
pub struct Level(log::Level);

impl FromStr for Level {
type Err = <log::Level as FromStr>::Err;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Level(log::Level::from_str(s)?))
}
}

impl From<log::Level> for Level {
fn from(value: log::Level) -> Self {
Self(value)
}
}

impl From<Level> for log::Level {
fn from(value: Level) -> Self {
value.0
}
}

#[derive(Clone, Debug, World)]
#[world(init = Self::new)]
struct LogWorld {
client: TestClient,
current_level: Option<Level>,
}

impl LogWorld {
fn new() -> Self {
let config = Config::load().expect("could not load config");
let client = TestClient::new(config.socket());
Self {
client,
current_level: None,
}
}
}

#[given(expr = "Espio doesn't know the log level")]
fn unknown_level(world: &mut LogWorld) {
world.current_level = None
}

#[when(expr = "Espio asks for the log level")]
#[given(expr = "the service's current log level")]
async fn get_log_level(world: &mut LogWorld) {
world.current_level = Some(
world
.client
.get_log_level()
.await
.expect("could not get log level")
.level
.into(),
)
}

#[when(expr = "Espio requests it changes to {level}")]
async fn set_log_level(world: &mut LogWorld, level: Level) {
world
.client
.set_log_level(level.into())
.await
.expect("problem setting log level");
}

#[then(expr = "Espio gets an answer")]
fn got_any_level(world: &mut LogWorld) {
assert!(
world.current_level.is_some(),
"did not get a valid level from the endpoint"
);
}

#[then(expr = "the log level is set to {level}")]
async fn got_expected_level(world: &mut LogWorld, level: Level) {
let post_set_level = world
.client
.get_log_level()
.await
.expect("could not get log level")
.level;

assert_eq!(level.0, post_set_level)
}

#[tokio::main]
async fn main() {
dotenvy::from_filename(".env_files/test.env").ok();

LogWorld::cucumber()
.repeat_skipped()
.init_tracing()
.max_concurrent_scenarios(1)
.run_and_exit("tests/features/admin/log-level.feature")
.await
}

0 comments on commit 732dbd4

Please sign in to comment.