1use serde::{Deserialize, Serialize};
6
7use crate::digest::Digest;
8
9#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
12pub struct BlobCheckRequest {
13 pub digests: Vec<Digest>,
14}
15
16#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
19pub struct BlobCheckResponse {
20 pub missing: Vec<Digest>,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27pub struct MissingBlob {
28 pub key: String,
29 pub digest: Digest,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36pub struct MissingBlobsError {
37 pub message: String,
38 pub missing: Vec<MissingBlob>,
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 fn digest(byte: u8) -> Digest {
46 Digest::from_sha256([byte; 32])
47 }
48
49 #[test]
50 fn blob_check_round_trips_through_json() {
51 let req = BlobCheckRequest {
52 digests: vec![digest(1), digest(2)],
53 };
54 let json = serde_json::to_string(&req).unwrap();
55 assert_eq!(
56 serde_json::from_str::<BlobCheckRequest>(&json).unwrap(),
57 req
58 );
59
60 let res = BlobCheckResponse {
61 missing: vec![digest(2)],
62 };
63 let json = serde_json::to_string(&res).unwrap();
64 assert_eq!(
65 serde_json::from_str::<BlobCheckResponse>(&json).unwrap(),
66 res
67 );
68 }
69
70 #[test]
71 fn empty_blob_check_response_means_nothing_is_missing() {
72 let res: BlobCheckResponse = serde_json::from_str(r#"{"missing":[]}"#).unwrap();
73 assert_eq!(res, BlobCheckResponse::default());
74 assert!(res.missing.is_empty());
75 }
76
77 #[test]
78 fn missing_blobs_error_round_trips_through_json() {
79 let err = MissingBlobsError {
80 message: "2 assets are not on the server".to_string(),
81 missing: vec![
82 MissingBlob {
83 key: "img/logo.png".to_string(),
84 digest: digest(1),
85 },
86 MissingBlob {
87 key: "typst/layouts/pdf/hero.typ".to_string(),
88 digest: digest(2),
89 },
90 ],
91 };
92
93 let json = serde_json::to_string(&err).unwrap();
94 assert_eq!(
95 serde_json::from_str::<MissingBlobsError>(&json).unwrap(),
96 err
97 );
98 }
99
100 #[test]
101 fn missing_blobs_error_rejects_an_invalid_digest() {
102 let err = serde_json::from_str::<MissingBlobsError>(
103 r#"{"message":"m","missing":[{"key":"k","digest":"NOPE"}]}"#,
104 )
105 .unwrap_err();
106 assert!(err.to_string().contains("64 hex characters"), "{err}");
107 }
108}