1use crate::api::channel::Channel;
2use crate::api::version::Version;
3use crate::api::{Download, API_BASE_URL};
4use crate::error::Result;
5use serde::Deserialize;
6use std::collections::HashMap;
7
8const LAST_KNOWN_GOOD_VERSIONS_WITH_DOWNLOADS_JSON_PATH: &str =
78 "/chrome-for-testing/last-known-good-versions-with-downloads.json";
79
80#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
83pub struct Downloads {
84 pub chrome: Vec<Download>,
86
87 pub chromedriver: Vec<Download>,
89
90 #[serde(rename = "chrome-headless-shell")]
95 pub chrome_headless_shell: Vec<Download>,
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
100pub struct VersionInChannel {
101 pub channel: Channel,
103
104 pub version: Version,
106
107 pub revision: String,
109
110 pub downloads: Downloads,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
118pub struct LastKnownGoodVersions {
119 #[serde(with = "time::serde::rfc3339")]
121 pub timestamp: time::OffsetDateTime,
122
123 pub channels: HashMap<Channel, VersionInChannel>,
125}
126
127impl LastKnownGoodVersions {
128 pub async fn fetch(client: reqwest::Client) -> Result<Self> {
132 Self::fetch_with_base_url(client, API_BASE_URL.clone()).await
133 }
134
135 pub async fn fetch_with_base_url(
136 client: reqwest::Client,
137 base_url: reqwest::Url,
138 ) -> Result<LastKnownGoodVersions> {
139 let last_known_good_versions = client
140 .get(base_url.join(LAST_KNOWN_GOOD_VERSIONS_WITH_DOWNLOADS_JSON_PATH)?)
141 .send()
142 .await?
143 .json::<Self>()
144 .await?;
145 Ok(last_known_good_versions)
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use crate::api::channel::Channel;
152 use crate::api::last_known_good_versions::{
153 Downloads, LastKnownGoodVersions, VersionInChannel,
154 LAST_KNOWN_GOOD_VERSIONS_WITH_DOWNLOADS_JSON_PATH,
155 };
156 use crate::api::platform::Platform;
157 use crate::api::version::Version;
158 use crate::api::Download;
159 use assertr::prelude::*;
160 use std::collections::HashMap;
161 use time::macros::datetime;
162 use url::Url;
163
164 #[tokio::test]
165 async fn can_request_from_real_world_endpoint() {
166 let result = LastKnownGoodVersions::fetch(reqwest::Client::new()).await;
167 assert_that(result).is_ok();
168 }
169
170 #[tokio::test]
172 async fn can_query_last_known_good_versions_api_endpoint_and_deserialize_response() {
173 let mut server = mockito::Server::new_async().await;
174
175 let _mock = server
176 .mock("GET", LAST_KNOWN_GOOD_VERSIONS_WITH_DOWNLOADS_JSON_PATH)
177 .with_status(200)
178 .with_header("content-type", "application/json")
179 .with_body(include_str!(
180 "./../../test-data/last_known_good_versions_test_response.json"
181 ))
182 .create();
183
184 let url: Url = server.url().parse().unwrap();
185
186 let data = LastKnownGoodVersions::fetch_with_base_url(reqwest::Client::new(), url)
187 .await
188 .unwrap();
189
190 assert_that(data).is_equal_to(LastKnownGoodVersions {
191 timestamp: datetime!(2025-01-17 10:09:31.683 UTC),
192 channels: HashMap::from([
193 (
194 Channel::Stable,
195 VersionInChannel {
196 channel: Channel::Stable,
197 version: Version { major: 132, minor: 0, patch: 6834, build: 83 },
198 revision: String::from("1381561"),
199 downloads: Downloads {
200 chrome: vec![
201 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/linux64/chrome-linux64.zip") },
202 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/mac-arm64/chrome-mac-arm64.zip") },
203 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/mac-x64/chrome-mac-x64.zip") },
204 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/win32/chrome-win32.zip") },
205 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/win64/chrome-win64.zip") },
206 ],
207 chromedriver: vec![
208 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/linux64/chromedriver-linux64.zip") },
209 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/mac-arm64/chromedriver-mac-arm64.zip") },
210 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/mac-x64/chromedriver-mac-x64.zip") },
211 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/win32/chromedriver-win32.zip") },
212 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/win64/chromedriver-win64.zip") },
213 ],
214 chrome_headless_shell: vec![
215 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/linux64/chrome-headless-shell-linux64.zip") },
216 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/mac-arm64/chrome-headless-shell-mac-arm64.zip") },
217 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/mac-x64/chrome-headless-shell-mac-x64.zip") },
218 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/win32/chrome-headless-shell-win32.zip") },
219 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.83/win64/chrome-headless-shell-win64.zip") },
220 ],
221 },
222 }
223 ),
224 (Channel::Beta, VersionInChannel {
225 channel: Channel::Beta,
226 version: Version { major: 133, minor: 0, patch: 6943, build: 16 },
227 revision: String::from("1402768"),
228 downloads: Downloads {
229 chrome: vec![
230 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/linux64/chrome-linux64.zip") },
231 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/mac-arm64/chrome-mac-arm64.zip") },
232 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/mac-x64/chrome-mac-x64.zip") },
233 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/win32/chrome-win32.zip") },
234 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/win64/chrome-win64.zip") },
235 ],
236 chromedriver: vec![
237 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/linux64/chromedriver-linux64.zip") },
238 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/mac-arm64/chromedriver-mac-arm64.zip") },
239 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/mac-x64/chromedriver-mac-x64.zip") },
240 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/win32/chromedriver-win32.zip") },
241 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/win64/chromedriver-win64.zip") },
242 ],
243 chrome_headless_shell: vec![
244 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/linux64/chrome-headless-shell-linux64.zip") },
245 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/mac-arm64/chrome-headless-shell-mac-arm64.zip") },
246 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/mac-x64/chrome-headless-shell-mac-x64.zip") },
247 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/win32/chrome-headless-shell-win32.zip") },
248 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/133.0.6943.16/win64/chrome-headless-shell-win64.zip") },
249 ],
250 },
251 }),
252 (Channel::Dev, VersionInChannel {
253 channel: Channel::Dev,
254 version: Version { major: 134, minor: 0, patch: 6958, build: 2 },
255 revision: String::from("1406477"),
256 downloads: Downloads {
257 chrome: vec![
258 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/linux64/chrome-linux64.zip") },
259 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/mac-arm64/chrome-mac-arm64.zip") },
260 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/mac-x64/chrome-mac-x64.zip") },
261 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/win32/chrome-win32.zip") },
262 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/win64/chrome-win64.zip") },
263 ],
264 chromedriver: vec![
265 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/linux64/chromedriver-linux64.zip") },
266 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/mac-arm64/chromedriver-mac-arm64.zip") },
267 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/mac-x64/chromedriver-mac-x64.zip") },
268 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/win32/chromedriver-win32.zip") },
269 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/win64/chromedriver-win64.zip") },
270 ],
271 chrome_headless_shell: vec![
272 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/linux64/chrome-headless-shell-linux64.zip") },
273 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/mac-arm64/chrome-headless-shell-mac-arm64.zip") },
274 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/mac-x64/chrome-headless-shell-mac-x64.zip") },
275 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/win32/chrome-headless-shell-win32.zip") },
276 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6958.2/win64/chrome-headless-shell-win64.zip") },
277 ],
278 },
279 }),
280 (Channel::Canary, VersionInChannel {
281 channel: Channel::Canary,
282 version: Version { major: 134, minor: 0, patch: 6962, build: 0 },
283 revision: String::from("1407692"),
284 downloads: Downloads {
285 chrome: vec![
286 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/linux64/chrome-linux64.zip") },
287 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/mac-arm64/chrome-mac-arm64.zip") },
288 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/mac-x64/chrome-mac-x64.zip") },
289 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win32/chrome-win32.zip") },
290 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win64/chrome-win64.zip") },
291 ],
292 chromedriver: vec![
293 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/linux64/chromedriver-linux64.zip") },
294 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/mac-arm64/chromedriver-mac-arm64.zip") },
295 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/mac-x64/chromedriver-mac-x64.zip") },
296 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win32/chromedriver-win32.zip") },
297 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win64/chromedriver-win64.zip") },
298 ],
299 chrome_headless_shell: vec![
300 Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/linux64/chrome-headless-shell-linux64.zip") },
301 Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/mac-arm64/chrome-headless-shell-mac-arm64.zip") },
302 Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/mac-x64/chrome-headless-shell-mac-x64.zip") },
303 Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win32/chrome-headless-shell-win32.zip") },
304 Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win64/chrome-headless-shell-win64.zip") },
305 ],
306 },
307 })
308 ]),
309 });
310 }
311}