Skip to content

Commit

Permalink
Implement feature to add strikes
Browse files Browse the repository at this point in the history
  • Loading branch information
tbsklg committed Aug 28, 2024
1 parent 5302429 commit c2e088c
Show file tree
Hide file tree
Showing 8 changed files with 1,076 additions and 72 deletions.
4 changes: 1 addition & 3 deletions cli-client/src/clients/client.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::collections::HashMap;

use async_trait::async_trait;

use crate::tarnished::Tarnished;

#[async_trait]
pub trait StrikeClient {
fn add_strike(&self, name: &str) -> HashMap<String, i8>;
async fn add_strike(&self, name: &str) -> Result<i8, String>;
fn get_tarnished(&self) -> Vec<Tarnished>;
fn clear_strikes(&self);
async fn check_health(&self) -> Result<(), String>;
Expand Down
71 changes: 42 additions & 29 deletions cli-client/src/clients/local_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct LocalClient {

#[async_trait]
impl StrikeClient for LocalClient {
fn add_strike(&self, name: &str) -> HashMap<String, i8> {
async fn add_strike(&self, name: &str) -> Result<i8, String> {
let db_path = &self.db_path;
if !db_path.exists() {
std::fs::create_dir_all(db_path.parent().unwrap()).unwrap();
Expand All @@ -24,7 +24,7 @@ impl StrikeClient for LocalClient {

std::fs::write(db_path, serde_json::to_string_pretty(&db).unwrap()).unwrap();

db.clone()
Ok(*db.get(name).unwrap())
}

fn get_tarnished(&self) -> Vec<Tarnished> {
Expand Down Expand Up @@ -54,22 +54,20 @@ impl StrikeClient for LocalClient {
mod unit_tests {
use super::*;

#[test]
fn it_should_add_a_strike_for_an_existing_name() -> Result<(), Box<dyn std::error::Error>> {
#[tokio::test]
async fn it_should_some_strikes() -> Result<(), Box<dyn std::error::Error>> {
let file = assert_fs::NamedTempFile::new("./tests/fixtures/db.json")?;
let client = LocalClient {
db_path: file.to_path_buf(),
};

client.add_strike("guenther");
let db = client.add_strike("heinz");
let _ = client.add_strike("guenther").await?;
let _ = client.add_strike("guenther").await?;
let strikes = client.add_strike("guenther").await?;

assert_eq!(
db,
[("guenther".to_string(), 1), ("heinz".to_string(), 1)]
.iter()
.cloned()
.collect()
strikes,
3,
);

Ok(())
Expand Down Expand Up @@ -109,38 +107,52 @@ mod unit_tests {

#[cfg(test)]
mod integration_tests {
use crate::clients::local_client::{LocalClient, StrikeClient as _};
use crate::{clients::local_client::{LocalClient, StrikeClient as _}, tarnished::Tarnished};

#[test]
fn it_should_add_a_strike() -> Result<(), Box<dyn std::error::Error>> {
#[tokio::test]
async fn it_should_add_a_strike() -> Result<(), Box<dyn std::error::Error>> {
let file = assert_fs::NamedTempFile::new("./tests/fixtures/db.json")?;
let client = LocalClient {
db_path: file.to_path_buf(),
};

let db = client.add_strike("guenther");
assert_eq!(db, [("guenther".to_string(), 1)].iter().cloned().collect());
let _ = client.add_strike("guenther").await?;
let strikes = client.get_tarnished();

assert_eq!(strikes, vec![
Tarnished {
name: "guenther".to_string(),
strikes: 1
}
]);
Ok(())
}

#[test]
fn it_should_add_a_strike_to_an_existing_db() -> Result<(), Box<dyn std::error::Error>> {
#[tokio::test]
async fn it_should_add_a_strike_to_an_existing_db() -> Result<(), Box<dyn std::error::Error>> {
let file = assert_fs::NamedTempFile::new("./tests/fixtures/db.json")?;
let client = LocalClient {
db_path: file.to_path_buf(),
};
client.add_strike("guenther");
client.add_strike("heinz");

let db = client.add_strike("guenther");

let _ = client.add_strike("guenther").await?;
let _ = client.add_strike("heinz").await?;
let _ = client.add_strike("guenther").await?;

let strikes = client.get_tarnished();

assert_eq!(
db,
[("guenther".to_string(), 2), ("heinz".to_string(), 1)]
.iter()
.cloned()
.collect()
strikes,
vec![
Tarnished {
name: "guenther".to_string(),
strikes: 2
},
Tarnished {
name: "heinz".to_string(),
strikes: 1
}
]
);

Ok(())
Expand All @@ -152,8 +164,9 @@ mod integration_tests {
let client = LocalClient {
db_path: file.to_path_buf(),
};
client.add_strike("guenther");
client.add_strike("heinz");

let _ = client.add_strike("guenther");
let _ = client.add_strike("heinz");

client.clear_strikes();

Expand Down
35 changes: 32 additions & 3 deletions cli-client/src/clients/remote_client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use async_trait::async_trait;
use reqwest;
use std::collections::HashMap;

use super::client::StrikeClient;
use crate::tarnished::Tarnished;
Expand All @@ -10,10 +9,20 @@ pub struct RemoteClient {
pub base_url: String,
}

#[derive(serde::Deserialize)]
struct StrikeResponse {
strike_count: i8,
}

#[async_trait]
impl StrikeClient for RemoteClient {
fn add_strike(&self, _name: &str) -> HashMap<String, i8> {
HashMap::new()
async fn add_strike(&self, username: &str) -> Result<i8, String> {
let client = HttpClient {
base_url: self.base_url.clone(),
api_key: self.api_key.clone(),
};

client.put_strike(username).await
}

fn get_tarnished(&self) -> Vec<Tarnished> {
Expand Down Expand Up @@ -56,4 +65,24 @@ impl HttpClient {
err => Err(err.to_string()),
}
}

async fn put_strike(&self, username: &str) -> Result<i8, String> {
let client = reqwest::Client::new();
let response = client
.put(format!("{}/strikes/{}", &self.base_url, username))
.header("x-api-key", &self.api_key)
.send()
.await
.expect("Failed to execute request");

match response.status() {
reqwest::StatusCode::OK => {
let body = response.text().await.expect("Failed to read response body");
Ok(serde_json::from_str::<StrikeResponse>(&body)
.expect("Failed to parse response")
.strike_count)
}
err => Err(err.to_string()),
}
}
}
8 changes: 4 additions & 4 deletions cli-client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ async fn main() {
let client = create_client(settings);

match &args.clone().command.unwrap() {
Command::Strike { name } => {
client.add_strike(name);
println!("{} has been tarnished!", name);
}
Command::Strike { name } => match client.add_strike(name).await {
Ok(strikes) => println!("{} has now {} strikes!", name, strikes),
Err(err) => eprintln!("Failed to add strike: {}", err),
},
Command::Ls => {
let tarnished = client.get_tarnished();

Expand Down
Loading

0 comments on commit c2e088c

Please sign in to comment.