Skip to main content

chrome_for_testing/api/
known_good_versions.rs

1use crate::api::version::Version;
2use crate::api::{API_BASE_URL, Download};
3use crate::error::Result;
4use serde::Deserialize;
5
6/// JSON Example:
7/// ```json
8/// {
9///     "version": "115.0.5763.0",
10///     "revision": "1141961",
11///     "downloads": {
12///         "chrome": [
13///             {
14///                 "platform": "linux64",
15///                 "url": "https://.../chrome-linux64.zip"
16///             },
17///             ...
18///         ],
19///         "chromedriver": [ /* <- Some versions don't have this field! */
20///             {
21///                 "platform": "linux64",
22///                 "url": "https://.../chromedriver-linux64.zip"
23///             },
24///             ...
25///         ]
26///     }
27/// },
28/// ```
29const KNOWN_GOOD_VERSIONS_WITH_DOWNLOADS_JSON_PATH: &str =
30    "/chrome-for-testing/known-good-versions-with-downloads.json";
31
32/// Download links for Chrome and `ChromeDriver` binaries.
33#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
34pub struct Downloads {
35    /// Download links for Chrome binaries for various platforms.
36    pub chrome: Vec<Download>,
37
38    /// Download links for `ChromeDriver` binaries for various platforms.
39    /// Note: Some older Chrome versions may not have `ChromeDriver` downloads available!
40    pub chromedriver: Option<Vec<Download>>,
41}
42
43/// An entry of the "known good versions" API response, representing one version.
44///
45/// No `Channel` information is provided.
46#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
47pub struct VersionWithoutChannel {
48    /// The version identifier.
49    pub version: Version,
50
51    /// The Chrome revision number.
52    pub revision: String,
53
54    /// Available downloads for this version.
55    pub downloads: Downloads,
56}
57
58/// Response structure for the "known good versions" API endpoint.
59///
60/// Contains a comprehensive list of Chrome versions that have been tested and verified to work.
61/// Unlike the "last known good versions" API, this includes all historical versions without
62/// channel assignments.
63#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
64pub struct KnownGoodVersions {
65    /// When this data was last updated.
66    #[serde(with = "time::serde::rfc3339")]
67    pub timestamp: time::OffsetDateTime,
68
69    /// List of all known good Chrome versions.
70    pub versions: Vec<VersionWithoutChannel>,
71}
72
73impl KnownGoodVersions {
74    /// Fetches the list of all known good Chrome versions from the Chrome for Testing API.
75    ///
76    /// Returns a comprehensive list of Chrome versions that have been tested and verified to work.
77    /// Unlike the "last known good versions" API, this includes all historical versions without
78    /// channel assignments.
79    ///
80    /// # Errors
81    ///
82    /// Returns an error if the HTTP request or deserialization fails.
83    pub async fn fetch(client: reqwest::Client) -> Result<Self> {
84        Self::fetch_with_base_url(client, API_BASE_URL.clone()).await
85    }
86
87    /// Fetches from a custom base URL (useful for testing).
88    ///
89    /// # Errors
90    ///
91    /// Returns an error if the HTTP request or deserialization fails.
92    pub async fn fetch_with_base_url(
93        client: reqwest::Client,
94        base_url: reqwest::Url,
95    ) -> Result<Self> {
96        let result = client
97            .get(base_url.join(KNOWN_GOOD_VERSIONS_WITH_DOWNLOADS_JSON_PATH)?)
98            .send()
99            .await?
100            .json::<Self>()
101            .await?;
102        Ok(result)
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use crate::api::Download;
110    use crate::api::known_good_versions::KnownGoodVersions;
111    use crate::api::platform::Platform;
112    use crate::api::version::Version;
113    use assertr::prelude::*;
114    use time::macros::datetime;
115    use url::Url;
116
117    #[tokio::test]
118    async fn can_request_from_real_world_endpoint() {
119        let result = KnownGoodVersions::fetch(reqwest::Client::new()).await;
120        assert_that!(result).is_ok();
121    }
122
123    //noinspection DuplicatedCode
124    #[tokio::test]
125    async fn can_query_known_good_versions_api_endpoint_and_deserialize_response() {
126        let mut server = mockito::Server::new_async().await;
127
128        let _mock = server
129            .mock("GET", KNOWN_GOOD_VERSIONS_WITH_DOWNLOADS_JSON_PATH)
130            .with_status(200)
131            .with_header("content-type", "application/json")
132            .with_body(include_str!(
133                "./../../test-data/known_good_versions_test_response.json"
134            ))
135            .create();
136
137        let url: Url = server.url().parse().unwrap();
138
139        let data = KnownGoodVersions::fetch_with_base_url(reqwest::Client::new(), url)
140            .await
141            .unwrap();
142
143        assert_that!(data).is_equal_to(KnownGoodVersions {
144            timestamp: datetime!(2025-01-17 10:09:31.689 UTC),
145            versions: vec![
146                VersionWithoutChannel {
147                    version: Version { major: 113, minor: 0, patch: 5672, build: 0 },
148                    revision: String::from("1121455"),
149                    downloads: Downloads {
150                        chrome: vec![
151                            Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/linux64/chrome-linux64.zip") },
152                            Download { platform: Platform::MacArm64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-arm64/chrome-mac-arm64.zip") },
153                            Download { platform: Platform::MacX64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-x64/chrome-mac-x64.zip") },
154                            Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win32/chrome-win32.zip") },
155                            Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win64/chrome-win64.zip") },
156                        ],
157                        chromedriver: None,
158                    },
159                },
160                VersionWithoutChannel {
161                    version: Version { major: 134, minor: 0, patch: 6962, build: 0 },
162                    revision: String::from("1407692"),
163                    downloads: Downloads {
164                        chrome: vec![
165                            Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/linux64/chrome-linux64.zip") },
166                            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") },
167                            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") },
168                            Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win32/chrome-win32.zip") },
169                            Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win64/chrome-win64.zip") },
170                        ],
171                        chromedriver: Some(vec![
172                            Download { platform: Platform::Linux64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/linux64/chromedriver-linux64.zip") },
173                            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") },
174                            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") },
175                            Download { platform: Platform::Win32, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win32/chromedriver-win32.zip") },
176                            Download { platform: Platform::Win64, url: String::from("https://storage.googleapis.com/chrome-for-testing-public/134.0.6962.0/win64/chromedriver-win64.zip") },
177                        ]),
178                    },
179                },
180            ],
181        });
182    }
183}