diff --git a/sqlx-data.json b/sqlx-data.json index 6247e93..802c4e0 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -87,22 +87,6 @@ "nullable": [] } }, - "3e31af624e06a2261fa85f25b5ec4c62a8408cd7283042e24b2aee2998931426": { - "query": "\nINSERT INTO survey_campaigns (\n user_id, ID, name, difficulties, created_at\n ) VALUES(\n (SELECT id FROM survey_admins WHERE name = $1),\n $2, $3, $4, $5\n );", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Uuid", - "Varchar", - "Int4Array", - "Timestamptz" - ] - }, - "nullable": [] - } - }, "43b3e771f38bf8059832169227705be06a28925af1b3799ffef5371d511fd138": { "query": "\n INSERT INTO survey_users (created_at, id) VALUES($1, $2)", "describe": { @@ -182,6 +166,22 @@ ] } }, + "82feafc36533144e49ba374c8c47ca4aa0d6558a9803778ad28cfa7b62382c3e": { + "query": "\n INSERT INTO survey_campaigns (\n user_id, ID, name, difficulties, created_at\n ) VALUES(\n (SELECT id FROM survey_admins WHERE name = $1),\n $2, $3, $4, $5\n );", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Uuid", + "Varchar", + "Int4Array", + "Timestamptz" + ] + }, + "nullable": [] + } + }, "8320dda2b3e107d1451fdfb35eb2a4b8e97364e7b1b74ffe4d6913faf132fb61": { "query": "SELECT ID \n FROM survey_responses \n WHERE \n user_id = $1 \n AND \n device_software_recognised = $2;", "describe": { diff --git a/src/api/v1/admin/campaigns.rs b/src/api/v1/admin/campaigns.rs index 623b7d1..02b4328 100644 --- a/src/api/v1/admin/campaigns.rs +++ b/src/api/v1/admin/campaigns.rs @@ -45,23 +45,25 @@ pub mod runners { pub async fn add_runner( username: &str, - payload: &AddCapmaign, + payload: &mut AddCapmaign, data: &AppData, ) -> ServiceResult { let mut uuid; let now = OffsetDateTime::now_utc(); + payload.difficulties.sort(); + loop { uuid = get_uuid(); let res = sqlx::query!( " -INSERT INTO survey_campaigns ( - user_id, ID, name, difficulties, created_at - ) VALUES( - (SELECT id FROM survey_admins WHERE name = $1), - $2, $3, $4, $5 - );", + INSERT INTO survey_campaigns ( + user_id, ID, name, difficulties, created_at + ) VALUES( + (SELECT id FROM survey_admins WHERE name = $1), + $2, $3, $4, $5 + );", username, &uuid, &payload.name, @@ -89,13 +91,19 @@ INSERT INTO survey_campaigns ( #[derive(Serialize, Deserialize)] pub struct AddCapmaign { - name: String, - difficulties: Vec, + pub name: String, + pub difficulties: Vec, +} + +#[derive(Serialize, Deserialize)] +pub struct AddCapmaignResp { + pub campaign_id: String, } pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(add); } + #[my_codegen::post(path = "crate::V1_API_ROUTES.admin.campaign.add")] async fn add( payload: web::Json, @@ -103,7 +111,82 @@ async fn add( id: Identity, ) -> ServiceResult { let username = id.identity().unwrap(); - let payload = payload.into_inner(); - let _campaign_id = runners::add_runner(&username, &payload, &data).await?; - Ok(HttpResponse::Ok()) + let mut payload = payload.into_inner(); + let campaign_id = runners::add_runner(&username, &mut payload, &data).await?; + let resp = AddCapmaignResp { + campaign_id: campaign_id.to_string(), + }; + Ok(HttpResponse::Ok().json(resp)) +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use crate::api::v1::bench::{Bench, BenchConfig, Submission, SubmissionProof}; + use crate::data::Data; + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn test_add_campaign() { + const NAME: &str = "testadminuser"; + const EMAIL: &str = "testuserupda@testadminuser.com"; + const PASSWORD: &str = "longpassword2"; + + const DEVICE_USER_PROVIDED: &str = "foo"; + const DEVICE_SOFTWARE_RECOGNISED: &str = "Foobar.v2"; + const THREADS: i32 = 4; + + let benches = vec![ + Bench { + difficulty: 1, + duration: 1.00, + }, + Bench { + difficulty: 2, + duration: 2.00, + }, + Bench { + difficulty: 3, + duration: 3.00, + }, + Bench { + difficulty: 4, + duration: 4.00, + }, + Bench { + difficulty: 5, + duration: 5.00, + }, + ]; + + { + let data = Data::new().await; + delete_user(NAME, &data).await; + } + + let (data, _creds, signin_resp) = + register_and_signin(NAME, EMAIL, PASSWORD).await; + let cookies = get_cookie!(signin_resp); + let survey = get_survey_user(data.clone()).await; + let survey_cookie = get_cookie!(survey); + // let app = get_app!(data).await; + + let campaign = create_new_campaign(NAME, data.clone(), cookies.clone()).await; + let campaign_config = + get_campaign_config(&campaign, data.clone(), survey_cookie.clone()).await; + + assert_eq!(DIFFICULTIES.to_vec(), campaign_config.difficulties); + + let submit_payload = Submission { + device_user_provided: DEVICE_USER_PROVIDED.into(), + device_software_recognised: DEVICE_SOFTWARE_RECOGNISED.into(), + threads: THREADS, + benches: benches.clone(), + }; + + let _proof = + submit_bench(&submit_payload, &campaign, survey_cookie, data.clone()).await; + } } diff --git a/src/api/v1/bench.rs b/src/api/v1/bench.rs index 8fdb5b4..b302231 100644 --- a/src/api/v1/bench.rs +++ b/src/api/v1/bench.rs @@ -99,31 +99,31 @@ pub mod runners { } } -#[my_codegen::post(path = "crate::V1_API_ROUTES.benches.register")] +#[my_codegen::get(path = "crate::V1_API_ROUTES.benches.register")] async fn register(data: AppData, id: Identity) -> ServiceResult { let uuid = runners::register_runner(&data).await?; id.remember(uuid.to_string()); Ok(HttpResponse::Ok()) } -#[derive(Serialize, Deserialize)] -struct Bench { - duration: f32, - difficulty: i32, +#[derive(Serialize, Deserialize, Clone)] +pub struct Bench { + pub duration: f32, + pub difficulty: i32, } -#[derive(Serialize, Deserialize)] -struct Submission { - device_user_provided: String, - device_software_recognised: String, - threads: i32, - benches: Vec, +#[derive(Serialize, Deserialize, Clone)] +pub struct Submission { + pub device_user_provided: String, + pub device_software_recognised: String, + pub threads: i32, + pub benches: Vec, } -#[derive(Serialize, Deserialize)] -struct SubmissionProof { - token: String, - proof: String, +#[derive(Serialize, Deserialize, Clone)] +pub struct SubmissionProof { + pub token: String, + pub proof: String, } fn get_check_login() -> crate::CheckLogin { diff --git a/src/tests.rs b/src/tests.rs index 3391245..c013030 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -14,15 +14,21 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +use std::str::FromStr; use std::sync::Arc; use actix_web::cookie::Cookie; use actix_web::test; use actix_web::{dev::ServiceResponse, error::ResponseError, http::StatusCode}; use serde::Serialize; +use uuid::Uuid; use super::*; -use crate::api::v1::admin::auth::runners::{Login, Register}; +use crate::api::v1::admin::{ + auth::runners::{Login, Register}, + campaigns::{AddCapmaign, AddCapmaignResp}, +}; +use crate::api::v1::bench::{Bench, BenchConfig, Submission, SubmissionProof}; use crate::data::Data; use crate::errors::*; use crate::V1_API_ROUTES; @@ -91,7 +97,7 @@ macro_rules! get_app { test::init_service(get_app!("APP")) }; ($data:expr) => { - test::init_service( + actix_web::test::init_service( get_app!("APP").app_data(actix_web::web::Data::new($data.clone())), ) }; @@ -192,29 +198,62 @@ pub async fn bad_post_req_test( // //println!("{}", txt.error); // assert_eq!(resp_err.error, format!("{}", err)); //} -// -//pub async fn create_new_campaign( -// campaign_name: &str, -// data: Arc, -// cookies: Cookie<'_>, -//) -> CreateResp { -// let new = CreateReq { -// name: campaign_name.into(), -// }; -// -// let app = get_app!(data).await; -// let new_resp = test::call_service( -// &app, -// post_request!(&new, crate::V1_API_ROUTES.campaign.new) -// .cookie(cookies) -// .to_request(), -// ) -// .await; -// assert_eq!(new_resp.status(), StatusCode::OK); -// let uuid: CreateResp = test::read_body_json(new_resp).await; -// uuid -//} -// + +pub const DIFFICULTIES: [i32; 5] = [1, 2, 3, 4, 5]; + +pub async fn create_new_campaign( + campaign_name: &str, + data: Arc, + cookies: Cookie<'_>, +) -> AddCapmaignResp { + let new = AddCapmaign { + name: campaign_name.into(), + difficulties: DIFFICULTIES.into(), + }; + + let app = get_app!(data).await; + let new_resp = test::call_service( + &app, + post_request!(&new, crate::V1_API_ROUTES.admin.campaign.add) + .cookie(cookies) + .to_request(), + ) + .await; + assert_eq!(new_resp.status(), StatusCode::OK); + let uuid: AddCapmaignResp = test::read_body_json(new_resp).await; + uuid +} + +pub async fn get_survey_user(data: Arc) -> ServiceResponse { + let app = get_app!(data).await; + let signin_resp = test::call_service( + &app, + test::TestRequest::get() + .uri(V1_API_ROUTES.benches.register) + .to_request(), + ) + .await; + + assert_eq!(signin_resp.status(), StatusCode::OK); + signin_resp +} + +pub async fn get_campaign_config( + campaign: &AddCapmaignResp, + data: Arc, + cookies: Cookie<'_>, +) -> BenchConfig { + let app = get_app!(data).await; + let route = V1_API_ROUTES + .benches + .fetch_routes(&campaign.campaign_id.to_string()); + let new_resp = + test::call_service(&app, post_request!(&route).cookie(cookies).to_request()) + .await; + assert_eq!(new_resp.status(), StatusCode::OK); + test::read_body_json(new_resp).await +} + //pub async fn delete_campaign( // camapign: &CreateResp, // data: Arc, @@ -244,22 +283,100 @@ pub async fn bad_post_req_test( // test::read_body_json(list_resp).await //} // -//pub async fn add_feedback( -// rating: &RatingReq, -// campaign: &CreateResp, -// data: Arc, -//) -> RatingResp { -// let add_feedback_route = V1_API_ROUTES.feedback.add_feedback_route(&campaign.uuid); -// let app = get_app!(data).await; -// let add_feedback_resp = test::call_service( -// &app, -// post_request!(&rating, &add_feedback_route).to_request(), -// ) -// .await; -// assert_eq!(add_feedback_resp.status(), StatusCode::OK); -// -// test::read_body_json(add_feedback_resp).await -//} +pub async fn submit_bench( + payload: &Submission, + campaign: &AddCapmaignResp, + cookies: Cookie<'_>, + data: Arc, +) -> SubmissionProof { + let route = V1_API_ROUTES.benches.submit_route(&campaign.campaign_id); + let app = get_app!(data).await; + let add_feedback_resp = test::call_service( + &app, + post_request!(&payload, &route).cookie(cookies).to_request(), + ) + .await; + assert_eq!(add_feedback_resp.status(), StatusCode::OK); + + let proof: SubmissionProof = test::read_body_json(add_feedback_resp).await; + + let survey_user_id = Uuid::from_str(&proof.token).unwrap(); + let proof_uuid = Uuid::from_str(&proof.proof).unwrap(); + + struct Exists { + exists: Option, + } + let res = sqlx::query_as!( + Exists, + "SELECT EXISTS ( + SELECT 1 from survey_responses + WHERE device_software_recognised = $1 + AND device_user_provided = $2 + AND THREADS = $3 + AND user_id = $4 + );", + &payload.device_software_recognised, + &payload.device_user_provided, + payload.threads, + &survey_user_id, + ) + .fetch_one(&data.db) + .await + .unwrap(); + assert!(res.exists.as_ref().unwrap()); + + let res = sqlx::query_as!( + Exists, + "SELECT EXISTS ( + SELECT 1 from survey_response_tokens + WHERE id = $1 + );", + &proof_uuid + ) + .fetch_one(&data.db) + .await + .unwrap(); + assert!(res.exists.as_ref().unwrap()); + + struct ID { + id: i32, + } + + let resp_id = sqlx::query_as!( + ID, + "SELECT ID + FROM survey_responses + WHERE + user_id = $1 + AND + device_software_recognised = $2;", + &survey_user_id, + &payload.device_software_recognised + ) + .fetch_one(&data.db) + .await + .unwrap(); + + for bench in payload.benches.iter() { + let res = sqlx::query_as!( + Exists, + "SELECT EXISTS( + SELECT 1 FROM survey_benches + WHERE resp_id = $1 + AND difficulty = $2 + AND duration = $3);", + &resp_id.id, + &bench.difficulty, + bench.duration + ) + .fetch_one(&data.db) + .await + .unwrap(); + assert!(res.exists.as_ref().unwrap()); + } + + proof +} // //pub async fn get_feedback( // campaign: &CreateResp,