diff options
| author | ojacobson <ojacobson@noreply.codeberg.org> | 2025-06-21 04:22:52 +0200 |
|---|---|---|
| committer | ojacobson <ojacobson@noreply.codeberg.org> | 2025-06-21 04:22:52 +0200 |
| commit | cd1dc0dab4b46bc5712070812192d5ce34071470 (patch) | |
| tree | c94f5a42f7e734b81892c1289a1d2b566706ba7c /src/channel/routes/test.rs | |
| parent | d84ba5cd09b713fac2f193d5c05af7415ea6742d (diff) | |
| parent | 4e3d5ccac99b24934c972e088cd7eb02bb95df06 (diff) | |
Reorganize and consolidate HTTP routes.
HTTP routes are now defined in a single, unified module, pulling them out of the topical modules they were formerly part of.
This is intended to improve the navigability of the codebase. Previously, finding the handler corresponding to a specific endpoint required prior familiarity, though in practice you could usually guess from topic area. Now, all routes are defined in one place; if you know the path, you can read down the list to find the handler.
Handlers themselves live with the domain they are most appropriately "part of," generally (in this version, universally) in a `handlers` submodule. The handlers themselves have been flattened down; rather than representing a path and a method, they now represent a named operation (which is suspiciously similar to the path in most cases). This means that we no longer have constructs like `crate::ui::routes::ch::channel` - it's now `crate::ui::handlers::channel` instead.
## Disclaimer
I Solemnly Swear I Didn't Change Any Handlers.
## Prior art
I've inadvertently reinvented Django's `urls.py` convention, and I've opted to lean into that.
Merges flatter-routes-reorg into main.
Diffstat (limited to 'src/channel/routes/test.rs')
| -rw-r--r-- | src/channel/routes/test.rs | 239 |
1 files changed, 0 insertions, 239 deletions
diff --git a/src/channel/routes/test.rs b/src/channel/routes/test.rs deleted file mode 100644 index cba8f2e..0000000 --- a/src/channel/routes/test.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::future; - -use axum::extract::{Json, State}; -use futures::stream::StreamExt as _; - -use super::post; -use crate::{ - channel::app, - name::Name, - test::fixtures::{self, future::Expect as _}, -}; - -#[tokio::test] -async fn new_channel() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let creator = fixtures::identity::create(&app, &fixtures::now()).await; - let resume_point = fixtures::boot::resume_point(&app).await; - - // Call the endpoint - - let name = fixtures::channel::propose(); - let request = post::Request { name: name.clone() }; - let post::Response(response) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) - .await - .expect("creating a channel in an empty app succeeds"); - - // Verify the structure of the response - - assert_eq!(name, response.name); - - // Verify the semantics - - let snapshot = app.boot().snapshot().await.expect("boot always succeeds"); - assert!(snapshot.channels.iter().any(|channel| channel == &response)); - - let channel = app - .channels() - .get(&response.id) - .await - .expect("the newly-created channel exists"); - assert_eq!(response, channel); - - let mut events = app - .events() - .subscribe(resume_point) - .await - .expect("subscribing never fails") - .filter_map(fixtures::event::channel) - .filter_map(fixtures::event::channel::created) - .filter(|event| future::ready(event.channel == response)); - - let event = events.next().expect_some("creation event published").await; - - assert_eq!(event.channel, response); -} - -#[tokio::test] -async fn duplicate_name() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let creator = fixtures::identity::create(&app, &fixtures::now()).await; - let channel = fixtures::channel::create(&app, &fixtures::now()).await; - - // Call the endpoint - - let request = post::Request { - name: channel.name.clone(), - }; - let post::Error(error) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) - .await - .expect_err("duplicate channel name should fail the request"); - - // Verify the structure of the response - - assert!(matches!( - error, - app::CreateError::DuplicateName(name) if channel.name == name - )); -} - -#[tokio::test] -async fn conflicting_canonical_name() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let creator = fixtures::identity::create(&app, &fixtures::now()).await; - - let existing_name = Name::from("rijksmuseum"); - app.channels() - .create(&existing_name, &fixtures::now()) - .await - .expect("creating a channel in an empty environment succeeds"); - - let conflicting_name = Name::from("r\u{0133}ksmuseum"); - - // Call the endpoint - - let request = post::Request { - name: conflicting_name.clone(), - }; - let post::Error(error) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) - .await - .expect_err("duplicate channel name should fail the request"); - - // Verify the structure of the response - - assert!(matches!( - error, - app::CreateError::DuplicateName(name) if conflicting_name == name - )); -} - -#[tokio::test] -async fn invalid_name() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let creator = fixtures::identity::create(&app, &fixtures::now()).await; - - // Call the endpoint - - let name = fixtures::channel::propose_invalid_name(); - let request = post::Request { name: name.clone() }; - let post::Error(error) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) - .await - .expect_err("invalid channel name should fail the request"); - - // Verify the structure of the response - - assert!(matches!( - error, - app::CreateError::InvalidName(error_name) if name == error_name - )); -} - -#[tokio::test] -async fn name_reusable_after_delete() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let creator = fixtures::identity::create(&app, &fixtures::now()).await; - let name = fixtures::channel::propose(); - - // Call the endpoint (first time) - - let request = post::Request { name: name.clone() }; - let post::Response(response) = post::handler( - State(app.clone()), - creator.clone(), - fixtures::now(), - Json(request), - ) - .await - .expect("new channel in an empty app"); - - // Delete the channel - - app.channels() - .delete(&response.id, &fixtures::now()) - .await - .expect("deleting a newly-created channel succeeds"); - - // Call the endpoint (second time) - - let request = post::Request { name: name.clone() }; - let post::Response(response) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) - .await - .expect("creation succeeds after original channel deleted"); - - // Verify the structure of the response - - assert_eq!(name, response.name); - - // Verify the semantics - - let channel = app - .channels() - .get(&response.id) - .await - .expect("the newly-created channel exists"); - assert_eq!(response, channel); -} - -#[tokio::test] -async fn name_reusable_after_expiry() { - // Set up the environment - - let app = fixtures::scratch_app().await; - let creator = fixtures::identity::create(&app, &fixtures::ancient()).await; - let name = fixtures::channel::propose(); - - // Call the endpoint (first time) - - let request = post::Request { name: name.clone() }; - let post::Response(_) = post::handler( - State(app.clone()), - creator.clone(), - fixtures::ancient(), - Json(request), - ) - .await - .expect("new channel in an empty app"); - - // Delete the channel - - app.channels() - .expire(&fixtures::now()) - .await - .expect("expiry always succeeds"); - - // Call the endpoint (second time) - - let request = post::Request { name: name.clone() }; - let post::Response(response) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) - .await - .expect("creation succeeds after original channel expired"); - - // Verify the structure of the response - - assert_eq!(name, response.name); - - // Verify the semantics - - let channel = app - .channels() - .get(&response.id) - .await - .expect("the newly-created channel exists"); - assert_eq!(response, channel); -} |
