From 62447a04dd59196109fb85849dc3aa98a1e45238 Mon Sep 17 00:00:00 2001 From: 0xMimir Date: Fri, 6 Oct 2023 19:11:49 +0200 Subject: [PATCH] added test for get --- .gitignore | 3 +- Cargo.toml | 4 +- api/src/api/cryptocurrencies/contract.rs | 10 ++- api/src/api/cryptocurrencies/handlers/get.rs | 4 +- api/src/api/cryptocurrencies/mod.rs | 2 +- api/src/api/kenobi.rs | 2 +- api/tests/setup.rs | 4 +- libs/error/src/lib.rs | 2 +- libs/sdks/src/coingecko/data.rs | 10 +-- libs/sdks/src/github/data.rs | 2 +- libs/sdks/src/github/domain.rs | 2 +- libs/sdks/tests/github.rs | 7 +- libs/store/src/objects/cryptocurrencies.rs | 2 +- libs/support/src/lib.rs | 2 +- libs/support/src/order.rs | 8 +- libs/support/src/pagination.rs | 8 +- .../2023-09-30-125034_cryptocurrencies/up.sql | 2 +- .../up.sql | 2 +- migrations/2023-10-01-145428_issues/up.sql | 2 +- tests/Cargo.toml | 7 ++ tests/src/cryptocurrencies/get.rs | 74 +++++++++++++++++++ tests/src/cryptocurrencies/mod.rs | 7 ++ tests/src/e2e_api.rs | 6 +- tests/src/lib.rs | 10 ++- tests/src/request.rs | 16 ++++ 25 files changed, 160 insertions(+), 38 deletions(-) create mode 100644 tests/src/cryptocurrencies/get.rs diff --git a/.gitignore b/.gitignore index eb21ebf..27d6024 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .env /.vscode tarpaulin-report.* -codecov \ No newline at end of file +codecov +trampolin.sh \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 02d1ed8..8090ed8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ sea-orm = { version = "0.12.3", features = [ "sqlx-postgres", ] } tokio = { version = "1.32.0", features = ["full"] } -reqwest = "0.11.20" +reqwest = { version = "0.11.20", features = ["json"] } serde = { version = "1.0.188", features = ["derive"] } serde_json = { version = "1.0.107" } thiserror = "1.0.49" @@ -21,6 +21,7 @@ actix = "0.13.1" actix-web = "4.4.0" utoipa = { version = "3.5.0", features = ["uuid", "actix_extras"] } validify = "1.0.11" +uuid = { version = "1.4.1", features = ["v4"] } error.path = "libs/error" sdks.path = "libs/sdks" @@ -28,3 +29,4 @@ store.path = "libs/store" config.path = "libs/config" api.path = "api" support.path = "libs/support" +adtest.git = "https://github.com/0xMimir/adtest.git" diff --git a/api/src/api/cryptocurrencies/contract.rs b/api/src/api/cryptocurrencies/contract.rs index fe04d95..d708bc9 100644 --- a/api/src/api/cryptocurrencies/contract.rs +++ b/api/src/api/cryptocurrencies/contract.rs @@ -12,12 +12,18 @@ use super::data::GetCryptoCurrenciesQuery; pub trait DbRepositoryContract { async fn get_issues_for_repository(&self, repository_id: Uuid) -> Result>; async fn get_cryptocurrency(&self, id: Uuid) -> Result; - async fn get_cryptocurrencies(&self, query: GetCryptoCurrenciesQuery) -> Result>; + async fn get_cryptocurrencies( + &self, + query: GetCryptoCurrenciesQuery, + ) -> Result>; } #[async_trait] pub trait CryptocurrenciesContract { async fn get_issues_for_repository(&self, repository_id: Uuid) -> Result>; async fn get_cryptocurrency(&self, id: Uuid) -> Result; - async fn get_cryptocurrencies(&self, query: GetCryptoCurrenciesQuery) -> Result>; + async fn get_cryptocurrencies( + &self, + query: GetCryptoCurrenciesQuery, + ) -> Result>; } diff --git a/api/src/api/cryptocurrencies/handlers/get.rs b/api/src/api/cryptocurrencies/handlers/get.rs index 7ccd46f..8852286 100644 --- a/api/src/api/cryptocurrencies/handlers/get.rs +++ b/api/src/api/cryptocurrencies/handlers/get.rs @@ -27,9 +27,7 @@ pub async fn get_cryptocurrencies( query.validate()?; let query = query.into_inner().into(); - let value = service - .get_cryptocurrencies(query) - .await?; + let value = service.get_cryptocurrencies(query).await?; Ok(HttpResponse::Ok().json(value)) } diff --git a/api/src/api/cryptocurrencies/mod.rs b/api/src/api/cryptocurrencies/mod.rs index ef7e047..2b71c91 100644 --- a/api/src/api/cryptocurrencies/mod.rs +++ b/api/src/api/cryptocurrencies/mod.rs @@ -6,8 +6,8 @@ use sea_orm::DatabaseConnection; use self::{domain::Cryptocurrencies, handlers::*, repository::PgRepository}; mod contract; -pub(super) mod docs; mod data; +pub(super) mod docs; mod domain; mod handlers; mod repository; diff --git a/api/src/api/kenobi.rs b/api/src/api/kenobi.rs index c02e787..ce5a95b 100644 --- a/api/src/api/kenobi.rs +++ b/api/src/api/kenobi.rs @@ -8,7 +8,7 @@ use actix_web::{get, HttpResponse}; #[get("/hello-there")] /// /// Route to know that api has started up -/// +/// pub async fn hello_there() -> HttpResponse { HttpResponse::Ok().body("General Kenobi") } diff --git a/api/tests/setup.rs b/api/tests/setup.rs index dfb6ec2..fe0a471 100644 --- a/api/tests/setup.rs +++ b/api/tests/setup.rs @@ -1,7 +1,7 @@ -use std::{sync::Arc, time::Duration}; use error::Result; use reqwest::get; use sea_orm::Database; +use std::{sync::Arc, time::Duration}; use tokio::time::sleep; #[tokio::test] @@ -24,7 +24,7 @@ async fn test_route_setup() -> Result<()> { .await? .text() .await?; - + assert_eq!(response, "General Kenobi"); handle.abort(); diff --git a/libs/error/src/lib.rs b/libs/error/src/lib.rs index fb589e9..3a87243 100644 --- a/libs/error/src/lib.rs +++ b/libs/error/src/lib.rs @@ -31,7 +31,7 @@ pub enum Error { Validation(#[from] validify::ValidationErrors), #[error("Unauthorized")] - Unauthorized + Unauthorized, } impl Error { diff --git a/libs/sdks/src/coingecko/data.rs b/libs/sdks/src/coingecko/data.rs index 8b1906d..8fd69d7 100644 --- a/libs/sdks/src/coingecko/data.rs +++ b/libs/sdks/src/coingecko/data.rs @@ -70,8 +70,8 @@ pub(crate) struct ErrorResponse { } #[derive(Deserialize)] -pub(crate) struct SimpleError{ - pub error: String +pub(crate) struct SimpleError { + pub error: String, } #[derive(Deserialize)] @@ -89,12 +89,12 @@ impl From for Error { } } -impl From for Error{ +impl From for Error { fn from(value: SimpleError) -> Self { - if value.error == "coin not found"{ + if value.error == "coin not found" { return Error::NotFound; } Self::InternalServer(value.error) } -} \ No newline at end of file +} diff --git a/libs/sdks/src/github/data.rs b/libs/sdks/src/github/data.rs index 35b185c..a9fc25c 100644 --- a/libs/sdks/src/github/data.rs +++ b/libs/sdks/src/github/data.rs @@ -28,7 +28,7 @@ impl From for Error { return Error::NotFound; } - if value.message == "Bad credentials"{ + if value.message == "Bad credentials" { return Error::Unauthorized; } diff --git a/libs/sdks/src/github/domain.rs b/libs/sdks/src/github/domain.rs index dcdeae7..f62b242 100644 --- a/libs/sdks/src/github/domain.rs +++ b/libs/sdks/src/github/domain.rs @@ -99,4 +99,4 @@ impl Github { Err(_) => Err(Error::InternalServer(response)), } } -} \ No newline at end of file +} diff --git a/libs/sdks/tests/github.rs b/libs/sdks/tests/github.rs index 5bc7c67..5dc08bf 100644 --- a/libs/sdks/tests/github.rs +++ b/libs/sdks/tests/github.rs @@ -1,4 +1,4 @@ -use error::{Result, Error}; +use error::{Error, Result}; use sdks::github::{Github, GithubContract}; #[tokio::test] @@ -31,7 +31,10 @@ async fn test_error_handling() -> Result<()> { assert!(matches!(error, Error::Unauthorized)); let github = Github::new(); - let error = github.get_repos("github-that-does-not-exist", 1).await.unwrap_err(); + let error = github + .get_repos("github-that-does-not-exist", 1) + .await + .unwrap_err(); assert!(matches!(error, Error::NotFoundWithCause(_))); Ok(()) diff --git a/libs/store/src/objects/cryptocurrencies.rs b/libs/store/src/objects/cryptocurrencies.rs index 6632aac..f6c09c5 100644 --- a/libs/store/src/objects/cryptocurrencies.rs +++ b/libs/store/src/objects/cryptocurrencies.rs @@ -1,6 +1,6 @@ use sea_orm::{prelude::Uuid, FromQueryResult}; -#[derive(FromQueryResult, Serialize)] +#[derive(FromQueryResult, Serialize, Deserialize)] pub struct CryptoCurrencyView { pub id: Uuid, pub name: String, diff --git a/libs/support/src/lib.rs b/libs/support/src/lib.rs index cc3ca0a..6934ab3 100644 --- a/libs/support/src/lib.rs +++ b/libs/support/src/lib.rs @@ -2,4 +2,4 @@ extern crate serde; pub mod order; -pub mod pagination; \ No newline at end of file +pub mod pagination; diff --git a/libs/support/src/order.rs b/libs/support/src/order.rs index 9dc3935..56c2290 100644 --- a/libs/support/src/order.rs +++ b/libs/support/src/order.rs @@ -5,11 +5,11 @@ pub enum Order { Desc, } -impl From for sea_orm::Order{ +impl From for sea_orm::Order { fn from(value: Order) -> Self { - match value{ + match value { Order::Asc => Self::Asc, - Order::Desc => Self::Desc + Order::Desc => Self::Desc, } } -} \ No newline at end of file +} diff --git a/libs/support/src/pagination.rs b/libs/support/src/pagination.rs index a889425..b4ccb75 100644 --- a/libs/support/src/pagination.rs +++ b/libs/support/src/pagination.rs @@ -1,9 +1,9 @@ -#[derive(Serialize)] -pub struct Pagination{ +#[derive(Serialize, Deserialize)] +pub struct Pagination { pub page: u64, pub per_page: u64, pub order_by: Vec, pub data: Vec, pub total_items: u64, - pub last_page: u64 -} \ No newline at end of file + pub last_page: u64, +} diff --git a/migrations/2023-09-30-125034_cryptocurrencies/up.sql b/migrations/2023-09-30-125034_cryptocurrencies/up.sql index 6005b4e..142e554 100644 --- a/migrations/2023-09-30-125034_cryptocurrencies/up.sql +++ b/migrations/2023-09-30-125034_cryptocurrencies/up.sql @@ -7,7 +7,7 @@ create table cryptocurrencies( id uuid primary key default uuid_generate_v4() not null, name varchar(255) not null unique, coingecko_id varchar(255) not null unique, - github uuid references github_projects(id), + github uuid references github_projects(id) on delete set null, gitlab varchar(255), description text ) \ No newline at end of file diff --git a/migrations/2023-10-01-102605_github-repositories/up.sql b/migrations/2023-10-01-102605_github-repositories/up.sql index f0f2b2d..fbdbb57 100644 --- a/migrations/2023-10-01-102605_github-repositories/up.sql +++ b/migrations/2023-10-01-102605_github-repositories/up.sql @@ -1,6 +1,6 @@ create table github_repositories( id uuid primary key default uuid_generate_v4() not null, - project uuid references github_projects(id) not null, + project uuid not null references github_projects(id) on delete cascade, repository_name varchar(255) not null, unique(project, repository_name) ) \ No newline at end of file diff --git a/migrations/2023-10-01-145428_issues/up.sql b/migrations/2023-10-01-145428_issues/up.sql index 2938395..f51e172 100644 --- a/migrations/2023-10-01-145428_issues/up.sql +++ b/migrations/2023-10-01-145428_issues/up.sql @@ -1,6 +1,6 @@ create table issues( id uuid primary key default uuid_generate_v4() not null, - repository uuid references github_repositories(id) not null, + repository uuid not null references github_repositories(id) on delete cascade, issue bigint not null, title text not null, description text, diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 1549168..21b7772 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -6,8 +6,15 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +adtest.workspace = true api.workspace = true config.workspace = true +error.workspace = true reqwest.workspace = true sea-orm.workspace = true +serde.workspace = true +serde_json.workspace = true +store.workspace = true +support.workspace = true tokio.workspace = true +uuid.workspace = true diff --git a/tests/src/cryptocurrencies/get.rs b/tests/src/cryptocurrencies/get.rs new file mode 100644 index 0000000..91bfbdc --- /dev/null +++ b/tests/src/cryptocurrencies/get.rs @@ -0,0 +1,74 @@ +use crate::request::request; +use error::Result; +use reqwest::Method; +use sea_orm::{ + prelude::Uuid, sea_query::OnConflict, DatabaseConnection, EntityTrait, ModelTrait, Set, +}; +use store::{cryptocurrencies, github_projects, github_repositories, objects::CryptoCurrencyView}; +use support::pagination::Pagination; + +/// +/// Test function for /api/v1/crypto +/// +pub async fn api_v1_crypto(sea_pool: &DatabaseConnection) { + let (github, crypto) = setup(sea_pool).await.unwrap(); + + let response: Pagination = + request("/api/v1/crypto", Method::GET, ()).await.unwrap(); + + assert!(!response.data.is_empty()); + + let response: Pagination = + request("/api/v1/crypto?search=oooooogggggaaaaa", Method::GET, ()) + .await + .unwrap(); + + assert!(response.data.is_empty()); + + github.delete(sea_pool).await.unwrap(); + crypto.delete(sea_pool).await.unwrap(); +} + +async fn setup( + sea_pool: &DatabaseConnection, +) -> Result<(github_projects::Model, cryptocurrencies::Model)> { + let github = github_projects::ActiveModel { + id: Set(Uuid::new_v4()), + name: Set("TestGit".to_owned()), + }; + + let github = github_projects::Entity::insert(github) + .on_conflict( + OnConflict::column(github_projects::Column::Name) + .do_nothing() + .to_owned(), + ) + .exec_with_returning(sea_pool) + .await?; + + let crypto = cryptocurrencies::ActiveModel { + id: Set(Uuid::new_v4()), + name: Set("Test coin 1000".to_owned()), + coingecko_id: Set("test-coin-at-coingecko".to_owned()), + github: Set(Some(github.id)), + ..Default::default() + }; + + let crypto = cryptocurrencies::Entity::insert(crypto) + .on_conflict(OnConflict::default().do_nothing().to_owned()) + .exec_with_returning(sea_pool) + .await?; + + let github_repo = github_repositories::ActiveModel { + project: Set(github.id), + repository_name: Set("good-repo".to_owned()), + ..Default::default() + }; + + github_repositories::Entity::insert(github_repo) + .on_conflict(OnConflict::default().do_nothing().to_owned()) + .exec(sea_pool) + .await?; + + Ok((github, crypto)) +} diff --git a/tests/src/cryptocurrencies/mod.rs b/tests/src/cryptocurrencies/mod.rs index e69de29..2ad1796 100644 --- a/tests/src/cryptocurrencies/mod.rs +++ b/tests/src/cryptocurrencies/mod.rs @@ -0,0 +1,7 @@ +use sea_orm::DatabaseConnection; + +mod get; + +pub async fn test(sea_pool: &DatabaseConnection) { + get::api_v1_crypto(sea_pool).await +} diff --git a/tests/src/e2e_api.rs b/tests/src/e2e_api.rs index 8e5babc..8924eef 100644 --- a/tests/src/e2e_api.rs +++ b/tests/src/e2e_api.rs @@ -2,11 +2,13 @@ use sea_orm::Database; use std::{sync::Arc, time::Duration}; use tokio::time::sleep; +use crate::cryptocurrencies; + #[tokio::test] async fn e2e_api() { let db_url = config::get("DATABASE_URL").unwrap(); let pool = Database::connect(db_url).await.unwrap(); - let sea_pool = Arc::new(pool); + let sea_pool = Arc::new(pool.clone()); let routes = api::create_api(sea_pool); @@ -14,5 +16,7 @@ async fn e2e_api() { sleep(Duration::from_secs(1)).await; + cryptocurrencies::test(&pool).await; + handle.abort(); } diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 45cf538..65525d8 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -1,5 +1,9 @@ -pub (crate) mod request; -pub(crate) mod cryptocurrencies; +#[allow(unused)] +#[macro_use] +extern crate adtest; + +pub mod cryptocurrencies; +pub mod request; #[cfg(test)] -mod e2e_api; \ No newline at end of file +mod e2e_api; diff --git a/tests/src/request.rs b/tests/src/request.rs index e69de29..984ec28 100644 --- a/tests/src/request.rs +++ b/tests/src/request.rs @@ -0,0 +1,16 @@ +use error::{Error, Result}; +use reqwest::{Client, Method}; +use serde::{de::DeserializeOwned, Serialize}; + +pub async fn request(url: U, method: Method, body: B) -> Result +where + U: Into, + B: Serialize, + R: DeserializeOwned + 'static, +{ + let client = Client::default(); + let url = format!("http://localhost:1111{}", url.into()); + let request = client.request(method, url).json(&body).send().await?; + let response_body = request.text().await?; + serde_json::from_str(&response_body).map_err(Error::from) +}