summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2024-05-07 16:56:48 -0500
committerToby Vincent <tobyv@tobyvin.dev>2024-05-07 16:56:48 -0500
commite56a04b88dfb8c141310a71d1a9c6b4be2fc9203 (patch)
tree72d8be549e5dd7e7564c085c7934dde339c0da44
parentb383010105b79fcd4e9d671ce82f5c04d0fc9b13 (diff)
feat(api): impl tests for tasks module
-rw-r--r--fixtures/tasks.sql10
-rw-r--r--src/api/tasks.rs160
2 files changed, 169 insertions, 1 deletions
diff --git a/fixtures/tasks.sql b/fixtures/tasks.sql
new file mode 100644
index 0000000..93d8a59
--- /dev/null
+++ b/fixtures/tasks.sql
@@ -0,0 +1,10 @@
+INSERT INTO task (id, user_id, title, description, remote, location, start_at, end_at) VALUES(
+ 'd5d31b54-0fc4-432c-9212-25175749c7f4',
+ '4c14f795-86f0-4361-a02f-0edb966fb145',
+ 'Unload Cargo',
+ 'I''ve got some cargo I need unloading.',
+ FALSE,
+ 'Astroid Gamma 2b, Madranite Mining Belt, 42d5b4, Orion Beta',
+ '2042-05-13 12:00:00 -5',
+ '2042-05-13 15:00:00 -5'
+);
diff --git a/src/api/tasks.rs b/src/api/tasks.rs
index 9a3e1ab..b8acd91 100644
--- a/src/api/tasks.rs
+++ b/src/api/tasks.rs
@@ -47,7 +47,7 @@ pub fn router() -> Resource<AppState> {
pub async fn create(
State(pool): State<PgPool>,
- _: AccessClaims,
+ AccessClaims { sub, .. }: AccessClaims,
Json(CreateTaskSchema {
user_id,
title,
@@ -58,6 +58,10 @@ pub async fn create(
end_at,
}): Json<CreateTaskSchema>,
) -> Result<(StatusCode, Json<Task>), Error> {
+ if sub != user_id {
+ return Err(Error::InvalidToken);
+ }
+
let task = sqlx::query_as!(Task,
"INSERT INTO task (user_id, title, description, remote, location, start_at, end_at) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *",
user_id,
@@ -102,3 +106,157 @@ pub async fn destroy(
.ok_or_else(|| Error::TaskNotFound)
.map(Json)
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use axum::{
+ body::Body,
+ http::{
+ header::{CONTENT_TYPE, COOKIE},
+ Request, StatusCode,
+ },
+ Router,
+ };
+
+ use http_body_util::BodyExt;
+ use time::macros::datetime;
+ use tower::ServiceExt;
+
+ use crate::{
+ auth::AccessClaims,
+ tests::{setup_test_env, TestResult},
+ };
+
+ const TASK_ID: Uuid = uuid::uuid!("d5d31b54-0fc4-432c-9212-25175749c7f4");
+ const TASK_USER_ID: Uuid = uuid::uuid!("4c14f795-86f0-4361-a02f-0edb966fb145");
+ const TASK_TITLE: &str = "Unload Cargo";
+ const TASK_DESCRIPTION: &str = r#"I've got some cargo I need unloading."#;
+ const TASK_REMOTE: bool = false;
+ const TASK_LOCATION: &str = "Astroid Gamma 2b, Madranite Mining Belt, 42d5b4, Orion Beta";
+ const TASK_START_AT: OffsetDateTime = datetime!(2042-05-13 12:00:00 -5);
+ const TASK_END_AT: OffsetDateTime = datetime!(2042-05-13 15:00:00 -5);
+
+ #[sqlx::test(fixtures(path = "../../fixtures", scripts("users")))]
+ async fn test_tasks_post_created(pool: PgPool) -> TestResult {
+ setup_test_env();
+
+ let router = Router::new().merge(router()).with_state(AppState { pool });
+
+ let task = serde_json::json!( {
+ "user_id": TASK_USER_ID,
+ "title": TASK_TITLE,
+ "description": TASK_DESCRIPTION,
+ "remote": TASK_REMOTE,
+ "location": TASK_LOCATION,
+ "start_at": TASK_START_AT,
+ "end_at": TASK_END_AT,
+ });
+
+ let request = Request::builder()
+ .method("POST")
+ .uri("/tasks")
+ .header(
+ COOKIE,
+ AccessClaims::issue(TASK_USER_ID).as_cookie()?.to_string(),
+ )
+ .header(CONTENT_TYPE, mime::APPLICATION_JSON.as_ref())
+ .body(Body::from(serde_json::to_vec(&task)?))?;
+
+ let response = router.oneshot(request).await?;
+
+ assert_eq!(
+ StatusCode::CREATED,
+ response.status(),
+ "{}",
+ std::str::from_utf8(&response.into_body().collect().await?.to_bytes())?
+ );
+
+ let body_bytes = response.into_body().collect().await?.to_bytes();
+ let Task {
+ user_id,
+ title,
+ description,
+ remote,
+ location,
+ start_at,
+ end_at,
+ ..
+ } = serde_json::from_slice(&body_bytes)?;
+
+ assert_eq!(Some(TASK_USER_ID), user_id);
+ assert_eq!(TASK_TITLE, title);
+ assert_eq!(Some(TASK_DESCRIPTION), description.as_deref());
+ assert_eq!(TASK_REMOTE, remote);
+ assert_eq!(Some(TASK_LOCATION), location.as_deref());
+ assert_eq!(Some(TASK_START_AT), start_at);
+ assert_eq!(Some(TASK_END_AT), end_at);
+
+ Ok(())
+ }
+
+ #[sqlx::test(fixtures(path = "../../fixtures", scripts("users", "tasks")))]
+ async fn test_tasks_get_ok(pool: PgPool) -> TestResult {
+ setup_test_env();
+
+ let router = Router::new().merge(router()).with_state(AppState { pool });
+
+ let request = Request::builder()
+ .uri(format!("/tasks/{}", TASK_ID))
+ .header(
+ COOKIE,
+ AccessClaims::issue(TASK_USER_ID).as_cookie()?.to_string(),
+ )
+ .body(Body::empty())?;
+
+ let response = router.oneshot(request).await?;
+
+ assert_eq!(StatusCode::OK, response.status());
+
+ let body_bytes = response.into_body().collect().await?.to_bytes();
+ let Task {
+ id,
+ user_id,
+ title,
+ description,
+ remote,
+ location,
+ start_at,
+ end_at,
+ ..
+ } = serde_json::from_slice(&body_bytes)?;
+
+ assert_eq!(TASK_ID, id);
+ assert_eq!(Some(TASK_USER_ID), user_id);
+ assert_eq!(TASK_TITLE, title);
+ assert_eq!(Some(TASK_DESCRIPTION), description.as_deref());
+ assert_eq!(TASK_REMOTE, remote);
+ assert_eq!(Some(TASK_LOCATION), location.as_deref());
+ assert_eq!(Some(TASK_START_AT), start_at);
+ assert_eq!(Some(TASK_END_AT), end_at);
+
+ Ok(())
+ }
+
+ #[sqlx::test]
+ async fn test_tasks_get_not_found(pool: PgPool) -> TestResult {
+ setup_test_env();
+
+ let router = Router::new().merge(router()).with_state(AppState { pool });
+
+ let request = Request::builder()
+ .uri(format!("/tasks/{}", TASK_ID))
+ .header(
+ COOKIE,
+ AccessClaims::issue(TASK_USER_ID).as_cookie()?.to_string(),
+ )
+ .body(Body::empty())?;
+
+ let response = router.oneshot(request).await?;
+
+ assert_eq!(StatusCode::NOT_FOUND, response.status());
+
+ Ok(())
+ }
+}