• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

divviup / divviup-api / 26255824633

21 May 2026 10:04PM UTC coverage: 68.771% (+0.4%) from 68.351%
26255824633

Pull #2266

github

web-flow
Merge 29b686e3e into 4070d0a1f
Pull Request #2266: Migrate from Trillium [part 9B]: Rewrite test infrastructure + remove all trillium deps

345 of 366 new or added lines in 14 files covered. (94.26%)

2 existing lines in 2 files now uncovered.

4422 of 6430 relevant lines covered (68.77%)

69.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.87
/src/api_mocks.rs
1
use axum::{
2
    extract::{Request, State},
3
    response::IntoResponse,
4
    Router,
5
};
6
use std::{collections::HashMap, sync::Arc};
7
use tower::ServiceExt;
8
use url::Url;
9

10
pub mod aggregator_api;
11
pub mod auth0;
12
pub mod postmark;
13

14
fn random_chars(n: usize) -> String {
141✔
15
    std::iter::repeat_with(fastrand::alphabetic)
141✔
16
        .take(n)
141✔
17
        .collect()
141✔
18
}
141✔
19

20
#[derive(Clone)]
21
struct HostMap {
22
    routers: HashMap<String, Router>,
23
    fallback: Router,
24
}
25

26
#[derive(Debug)]
27
pub struct ApiMocks {
28
    router: Router,
29
}
30

31
impl ApiMocks {
32
    pub fn new(postmark_url: &str, auth0_url: &str) -> Self {
274✔
33
        let mut routers = HashMap::new();
274✔
34
        routers.insert(extract_host(postmark_url), postmark::mock());
274✔
35
        routers.insert(extract_host(auth0_url), auth0::mock(auth0_url));
274✔
36

37
        let host_map = Arc::new(HostMap {
274✔
38
            routers,
274✔
39
            fallback: aggregator_api::mock(),
274✔
40
        });
274✔
41

42
        let router = Router::new()
274✔
43
            .fallback(dispatch_by_host)
274✔
44
            .with_state(host_map);
274✔
45

46
        Self { router }
274✔
47
    }
274✔
48

49
    pub fn into_router(self) -> Router {
274✔
50
        self.router
274✔
51
    }
274✔
52
}
53

54
// NB: Url::host_str() strips IPv6 brackets, but the Host header keeps them.
55
// Current callers only pass hostname URLs, so this doesn't bite today.
56
fn extract_host(url: &str) -> String {
548✔
57
    Url::parse(url)
548✔
58
        .ok()
548✔
59
        .and_then(|u| {
548✔
60
            u.host_str().map(|h| match u.port() {
548✔
NEW
61
                Some(p) => format!("{h}:{p}"),
×
62
                None => h.to_string(),
548✔
63
            })
548✔
64
        })
548✔
65
        .unwrap_or_default()
548✔
66
        .to_lowercase()
548✔
67
}
548✔
68

69
async fn dispatch_by_host(State(host_map): State<Arc<HostMap>>, req: Request) -> impl IntoResponse {
79✔
70
    let host = req
79✔
71
        .headers()
79✔
72
        .get("host")
79✔
73
        .and_then(|h| h.to_str().ok())
79✔
74
        .unwrap_or("")
79✔
75
        .to_lowercase();
79✔
76

77
    let router = host_map
79✔
78
        .routers
79✔
79
        .get(&host)
79✔
80
        .unwrap_or(&host_map.fallback)
79✔
81
        .clone();
79✔
82

83
    router.oneshot(req).await.into_response()
79✔
84
}
79✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc