pulith_fetch/config/
sources.rs1#[derive(Clone, Debug, PartialEq, Eq)]
3pub struct DownloadSource {
4 pub url: String,
6
7 pub priority: u32,
9
10 pub checksum: Option<[u8; 32]>,
12
13 pub source_type: SourceType,
15
16 pub region: Option<String>,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub enum SourceType {
22 Primary,
24
25 Mirror,
27
28 Cdn,
30
31 Fallback,
33}
34
35impl DownloadSource {
36 pub fn new(url: impl Into<String>) -> Self {
37 Self {
38 url: url.into(),
39 priority: 0,
40 checksum: None,
41 source_type: SourceType::Primary,
42 region: None,
43 }
44 }
45
46 pub fn priority(mut self, priority: u32) -> Self {
47 self.priority = priority;
48 self
49 }
50
51 pub fn checksum(mut self, checksum: [u8; 32]) -> Self {
52 self.checksum = Some(checksum);
53 self
54 }
55
56 pub fn source_type(mut self, source_type: SourceType) -> Self {
57 self.source_type = source_type;
58 self
59 }
60
61 pub fn region(mut self, region: impl Into<String>) -> Self {
62 self.region = Some(region.into());
63 self
64 }
65}
66
67#[derive(Clone, Debug)]
69pub struct MultiSourceOptions {
70 pub sources: Vec<DownloadSource>,
72
73 pub strategy: SourceSelectionStrategy,
75
76 pub verify_consistency: bool,
78
79 pub per_source_timeout: Option<std::time::Duration>,
81}
82
83#[derive(Clone, Debug, PartialEq, Eq)]
84pub enum SourceSelectionStrategy {
85 Priority,
87
88 FastestFirst,
90
91 Geographic,
93
94 RaceAll,
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_download_source_new() {
104 let source = DownloadSource::new("https://example.com/file");
105 assert_eq!(source.url, "https://example.com/file");
106 assert_eq!(source.priority, 0);
107 assert!(source.checksum.is_none());
108 assert_eq!(source.source_type, SourceType::Primary);
109 assert!(source.region.is_none());
110 }
111
112 #[test]
113 fn test_download_source_builder() {
114 let checksum = [1u8; 32];
115 let source = DownloadSource::new("https://example.com/file")
116 .priority(5)
117 .checksum(checksum)
118 .source_type(SourceType::Mirror)
119 .region("us-west");
120
121 assert_eq!(source.url, "https://example.com/file");
122 assert_eq!(source.priority, 5);
123 assert_eq!(source.checksum, Some(checksum));
124 assert_eq!(source.source_type, SourceType::Mirror);
125 assert_eq!(source.region, Some("us-west".to_string()));
126 }
127
128 #[test]
129 fn test_download_source_clone() {
130 let source = DownloadSource::new("https://example.com/file")
131 .priority(3)
132 .source_type(SourceType::Cdn);
133
134 let cloned = source.clone();
135 assert_eq!(cloned, source);
136 }
137
138 #[test]
139 fn test_source_type_equality() {
140 assert_eq!(SourceType::Primary, SourceType::Primary);
141 assert_ne!(SourceType::Primary, SourceType::Mirror);
142 assert_ne!(SourceType::Mirror, SourceType::Cdn);
143 assert_ne!(SourceType::Cdn, SourceType::Fallback);
144 }
145
146 #[test]
147 fn test_multi_source_options_default() {
148 let options = MultiSourceOptions {
150 sources: vec![],
151 strategy: SourceSelectionStrategy::Priority,
152 verify_consistency: false,
153 per_source_timeout: None,
154 };
155
156 assert!(options.sources.is_empty());
157 assert_eq!(options.strategy, SourceSelectionStrategy::Priority);
158 assert!(!options.verify_consistency);
159 assert!(options.per_source_timeout.is_none());
160 }
161
162 #[test]
163 fn test_multi_source_options_with_sources() {
164 let source1 = DownloadSource::new("https://primary.example.com")
165 .priority(0)
166 .source_type(SourceType::Primary);
167
168 let source2 = DownloadSource::new("https://mirror.example.com")
169 .priority(1)
170 .source_type(SourceType::Mirror)
171 .region("eu");
172
173 let options = MultiSourceOptions {
174 sources: vec![source1.clone(), source2.clone()],
175 strategy: SourceSelectionStrategy::FastestFirst,
176 verify_consistency: true,
177 per_source_timeout: Some(std::time::Duration::from_secs(30)),
178 };
179
180 assert_eq!(options.sources.len(), 2);
181 assert_eq!(options.sources[0], source1);
182 assert_eq!(options.sources[1], source2);
183 assert_eq!(options.strategy, SourceSelectionStrategy::FastestFirst);
184 assert!(options.verify_consistency);
185 assert_eq!(
186 options.per_source_timeout,
187 Some(std::time::Duration::from_secs(30))
188 );
189 }
190
191 #[test]
192 fn test_source_selection_strategies() {
193 let strategies = [
194 SourceSelectionStrategy::Priority,
195 SourceSelectionStrategy::FastestFirst,
196 SourceSelectionStrategy::Geographic,
197 SourceSelectionStrategy::RaceAll,
198 ];
199
200 for (i, strategy1) in strategies.iter().enumerate() {
202 for (j, strategy2) in strategies.iter().enumerate() {
203 if i != j {
204 assert_ne!(strategy1, strategy2);
205 }
206 }
207 }
208 }
209
210 #[test]
211 fn test_download_source_with_string_conversion() {
212 let url_string = "https://example.com/file".to_string();
213 let source = DownloadSource::new(url_string.clone());
214 assert_eq!(source.url, url_string);
215
216 let region_string = "us-east".to_string();
217 let source_with_region = source.region(region_string.clone());
218 assert_eq!(source_with_region.region, Some(region_string));
219 }
220
221 #[test]
222 fn test_download_source_debug() {
223 let source = DownloadSource::new("https://example.com/file")
224 .priority(2)
225 .source_type(SourceType::Cdn)
226 .region("us-west");
227
228 let debug_str = format!("{:?}", source);
229 assert!(debug_str.contains("DownloadSource"));
230 assert!(debug_str.contains("https://example.com/file"));
231 assert!(debug_str.contains("priority: 2"));
232 assert!(debug_str.contains("Cdn"));
233 assert!(debug_str.contains("us-west"));
234 }
235
236 #[test]
237 fn test_multi_source_options_debug() {
238 let options = MultiSourceOptions {
239 sources: vec![DownloadSource::new("https://example.com")],
240 strategy: SourceSelectionStrategy::RaceAll,
241 verify_consistency: true,
242 per_source_timeout: Some(std::time::Duration::from_secs(60)),
243 };
244
245 let debug_str = format!("{:?}", options);
246 assert!(debug_str.contains("MultiSourceOptions"));
247 assert!(debug_str.contains("RaceAll"));
248 assert!(debug_str.contains("verify_consistency: true"));
249 }
250}