Skip to content

Commit 9b451e0

Browse files
committed
Allow semver in status paths
1 parent 8b388a7 commit 9b451e0

File tree

2 files changed

+89
-89
lines changed

2 files changed

+89
-89
lines changed

src/web/mod.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,6 @@ impl MatchSemver {
116116
| MatchSemver::Latest((v, i)) => (v, i),
117117
}
118118
}
119-
120-
/// If the matched version was an exact match to a semver version, returns the
121-
/// version string and id for the query. If the lookup required a semver match, returns
122-
/// `VersionNotFound`.
123-
fn exact_version_only(self) -> Result<(String, i32), AxumNope> {
124-
let MatchSemver::Exact(details) = self else { return Err(AxumNope::VersionNotFound) };
125-
Ok(details)
126-
}
127119
}
128120

129121
/// Checks the database for crate releases that match the given name and version.

src/web/status.rs

Lines changed: 89 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,48 @@ use axum::{
1212
};
1313

1414
pub(crate) async fn status_handler(
15-
Path((name, req_version)): Path<(String, String)>,
16-
Extension(pool): Extension<Pool>,
17-
) -> AxumResult<impl IntoResponse> {
18-
let (_, id) = match_version_axum(&pool, &name, Some(&req_version))
19-
.await?
20-
.exact_name_only()?
21-
.exact_version_only()?;
22-
23-
let rustdoc_status: bool = spawn_blocking({
24-
move || {
25-
Ok(pool
26-
.get()?
27-
.query_one(
28-
"SELECT releases.rustdoc_status
29-
FROM releases
30-
WHERE releases.id = $1
31-
",
32-
&[&id],
33-
)?
34-
.get("rustdoc_status"))
35-
}
36-
})
37-
.await?;
38-
39-
Ok((
15+
path: Path<(String, String)>,
16+
pool: Extension<Pool>,
17+
) -> impl IntoResponse {
18+
async fn inner(
19+
Path((name, req_version)): Path<(String, String)>,
20+
Extension(pool): Extension<Pool>,
21+
) -> AxumResult<impl IntoResponse> {
22+
let (version, id) = match_version_axum(&pool, &name, Some(&req_version))
23+
.await?
24+
.exact_name_only()?
25+
.into_parts();
26+
27+
let rustdoc_status: bool = spawn_blocking({
28+
move || {
29+
Ok(pool
30+
.get()?
31+
.query_one(
32+
"SELECT releases.rustdoc_status
33+
FROM releases
34+
WHERE releases.id = $1
35+
",
36+
&[&id],
37+
)?
38+
.get("rustdoc_status"))
39+
}
40+
})
41+
.await?;
42+
43+
Ok((
44+
Extension(CachePolicy::NoStoreMustRevalidate),
45+
[(ACCESS_CONTROL_ALLOW_ORIGIN, "*")],
46+
Json(serde_json::json!({
47+
"version": version,
48+
"doc_status": rustdoc_status,
49+
})),
50+
))
51+
}
52+
(
4053
Extension(CachePolicy::NoStoreMustRevalidate),
4154
[(ACCESS_CONTROL_ALLOW_ORIGIN, "*")],
42-
Json(serde_json::json!({ "doc_status": rustdoc_status })),
43-
))
55+
inner(path, pool).await,
56+
)
4457
}
4558

4659
#[cfg(test)]
@@ -50,93 +63,88 @@ mod tests {
5063
web::cache::CachePolicy,
5164
};
5265
use reqwest::StatusCode;
66+
use test_case::test_case;
5367

54-
#[test]
55-
fn success() {
68+
#[test_case("latest")]
69+
#[test_case("0.1")]
70+
#[test_case("0.1.0")]
71+
fn status(version: &str) {
5672
wrapper(|env| {
5773
env.fake_release().name("foo").version("0.1.0").create()?;
5874

59-
let response = env.frontend().get("/crate/foo/0.1.0/status.json").send()?;
75+
let response = env
76+
.frontend()
77+
.get(&format!("/crate/foo/{version}/status.json"))
78+
.send()?;
6079
assert_cache_control(&response, CachePolicy::NoStoreMustRevalidate, &env.config());
6180
assert_eq!(response.headers()["access-control-allow-origin"], "*");
81+
assert_eq!(response.status(), StatusCode::OK);
6282
let value: serde_json::Value = serde_json::from_str(&response.text()?)?;
6383

64-
assert_eq!(value, serde_json::json!({"doc_status": true}));
84+
assert_eq!(
85+
value,
86+
serde_json::json!({
87+
"version": "0.1.0",
88+
"doc_status": true,
89+
})
90+
);
6591

6692
Ok(())
6793
});
6894
}
6995

70-
#[test]
71-
fn failure() {
96+
#[test_case("latest")]
97+
#[test_case("0.1")]
98+
#[test_case("0.1.0")]
99+
fn failure(version: &str) {
72100
wrapper(|env| {
73101
env.fake_release()
74102
.name("foo")
75103
.version("0.1.0")
76104
.build_result_failed()
77105
.create()?;
78106

79-
let response = env.frontend().get("/crate/foo/0.1.0/status.json").send()?;
107+
let response = env
108+
.frontend()
109+
.get(&format!("/crate/foo/{version}/status.json"))
110+
.send()?;
80111
assert_cache_control(&response, CachePolicy::NoStoreMustRevalidate, &env.config());
81112
assert_eq!(response.headers()["access-control-allow-origin"], "*");
113+
assert_eq!(response.status(), StatusCode::OK);
82114
let value: serde_json::Value = serde_json::from_str(&response.text()?)?;
83115

84-
assert_eq!(value, serde_json::json!({"doc_status": false}));
85-
86-
Ok(())
87-
});
88-
}
89-
90-
#[test]
91-
fn crate_version_not_found() {
92-
wrapper(|env| {
93-
env.fake_release().name("foo").version("0.1.0").create()?;
94-
95-
let response = env.frontend().get("/crate/foo/0.2.0/status.json").send()?;
96-
assert!(response
97-
.url()
98-
.as_str()
99-
.ends_with("/crate/foo/0.2.0/status.json"));
100-
assert_eq!(response.status(), StatusCode::NOT_FOUND);
101-
Ok(())
102-
});
103-
}
104-
105-
#[test]
106-
fn invalid_semver() {
107-
wrapper(|env| {
108-
env.fake_release().name("foo").version("0.1.0").create()?;
116+
assert_eq!(
117+
value,
118+
serde_json::json!({
119+
"version": "0.1.0",
120+
"doc_status": false,
121+
})
122+
);
109123

110-
let response = env.frontend().get("/crate/foo/0,1,0/status.json").send()?;
111-
assert!(response
112-
.url()
113-
.as_str()
114-
.ends_with("/crate/foo/0,1,0/status.json"));
115-
assert_eq!(response.status(), StatusCode::NOT_FOUND);
116124
Ok(())
117125
});
118126
}
119127

120-
/// We only support asking for the status of exact versions
121-
#[test]
122-
fn no_semver() {
128+
// crate not found
129+
#[test_case("bar", "0.1")]
130+
#[test_case("bar", "0.1.0")]
131+
// version not found
132+
#[test_case("foo", "0.2")]
133+
#[test_case("foo", "0.2.0")]
134+
// invalid semver
135+
#[test_case("foo", "0,1")]
136+
#[test_case("foo", "0,1,0")]
137+
fn not_found(krate: &str, version: &str) {
123138
wrapper(|env| {
124139
env.fake_release().name("foo").version("0.1.0").create()?;
125140

126-
let response = env.frontend().get("/crate/foo/latest/status.json").send()?;
127-
assert!(response
128-
.url()
129-
.as_str()
130-
.ends_with("/crate/foo/latest/status.json"));
131-
assert_eq!(response.status(), StatusCode::NOT_FOUND);
132-
133-
let response = env.frontend().get("/crate/foo/0.1/status.json").send()?;
134-
assert!(response
135-
.url()
136-
.as_str()
137-
.ends_with("/crate/foo/0.1/status.json"));
141+
let response = env
142+
.frontend()
143+
.get(&format!("/crate/{krate}/{version}/status.json"))
144+
.send()?;
145+
assert_cache_control(&response, CachePolicy::NoStoreMustRevalidate, &env.config());
146+
assert_eq!(response.headers()["access-control-allow-origin"], "*");
138147
assert_eq!(response.status(), StatusCode::NOT_FOUND);
139-
140148
Ok(())
141149
});
142150
}

0 commit comments

Comments
 (0)