Skip to content

Commit c483b0f

Browse files
authored
[rust] Selenium Manager parse mirror to get latest IEDriverServer version (#11672)
[rust] Selenium Manager parse mirror to get latest IEDriverServer version (part of #11672)
1 parent 906baa8 commit c483b0f

File tree

8 files changed

+159
-25
lines changed

8 files changed

+159
-25
lines changed

rust/src/chrome.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use std::path::PathBuf;
2323

2424
use crate::config::ARCH::ARM64;
2525
use crate::config::OS::{LINUX, MACOS, WINDOWS};
26-
use crate::downloads::read_content_from_link;
26+
use crate::downloads::read_version_from_link;
2727
use crate::files::{compose_driver_path_in_cache, BrowserPath, PARSE_ERROR};
2828
use crate::logger::Logger;
2929
use crate::metadata::{
@@ -176,7 +176,7 @@ impl SeleniumManager for ChromeManager {
176176
"Reading {} version from {}",
177177
&self.driver_name, driver_url
178178
));
179-
match read_content_from_link(self.get_http_client(), driver_url) {
179+
match read_version_from_link(self.get_http_client(), driver_url) {
180180
Ok(version) => {
181181
driver_version = version;
182182
break;

rust/src/downloads.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,16 @@ pub async fn download_driver_to_tmp_folder(
6565
Ok((tmp_dir, target_path))
6666
}
6767

68+
pub fn read_version_from_link(http_client: &Client, url: String) -> Result<String, Box<dyn Error>> {
69+
parse_version(read_content_from_link(http_client, url)?)
70+
}
71+
6872
#[tokio::main]
6973
pub async fn read_content_from_link(
7074
http_client: &Client,
7175
url: String,
7276
) -> Result<String, Box<dyn Error>> {
73-
parse_version(http_client.get(url).send().await?.text().await?)
77+
Ok(http_client.get(url).send().await?.text().await?)
7478
}
7579

7680
#[tokio::main]

rust/src/edge.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use std::path::PathBuf;
2323

2424
use crate::config::ARCH::{ARM64, X32};
2525
use crate::config::OS::{LINUX, MACOS, WINDOWS};
26-
use crate::downloads::read_content_from_link;
26+
use crate::downloads::read_version_from_link;
2727
use crate::files::{compose_driver_path_in_cache, BrowserPath};
2828
use crate::metadata::{
2929
create_driver_metadata, get_driver_version_from_metadata, get_metadata, write_metadata,
@@ -176,7 +176,7 @@ impl SeleniumManager for EdgeManager {
176176
"Reading {} version from {}",
177177
&self.driver_name, driver_url
178178
));
179-
let driver_version = read_content_from_link(self.get_http_client(), driver_url)?;
179+
let driver_version = read_version_from_link(self.get_http_client(), driver_url)?;
180180

181181
if !browser_version.is_empty() {
182182
metadata.drivers.push(create_driver_metadata(

rust/src/files.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,5 +192,8 @@ pub fn parse_version(version_text: String) -> Result<String, Box<dyn Error>> {
192192
break;
193193
}
194194
}
195+
if parsed_version.ends_with('.') {
196+
parsed_version = parsed_version[0..parsed_version.len() - 1].to_string();
197+
}
195198
Ok(parsed_version)
196199
}

rust/src/iexplorer.rs

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@
1717

1818
use crate::config::ManagerConfig;
1919
use reqwest::Client;
20+
use std::cell::RefCell;
2021
use std::collections::HashMap;
2122
use std::error::Error;
2223
use std::path::PathBuf;
2324

24-
use crate::downloads::read_redirect_from_link;
2525
use crate::files::{compose_driver_path_in_cache, BrowserPath};
2626

27-
use crate::{create_default_http_client, Logger, SeleniumManager};
27+
use crate::{create_default_http_client, parse_version, Logger, SeleniumManager};
2828

2929
use crate::metadata::{
3030
create_driver_metadata, get_driver_version_from_metadata, get_metadata, write_metadata,
3131
};
32+
use crate::mirror::{get_mirror_response, Assets, SeleniumRelease};
3233

3334
pub const IE_NAMES: &[&str] = &[
3435
"iexplorer",
@@ -39,7 +40,9 @@ pub const IE_NAMES: &[&str] = &[
3940
];
4041
pub const IEDRIVER_NAME: &str = "IEDriverServer";
4142
const DRIVER_URL: &str = "https://github.com/SeleniumHQ/selenium/releases/";
42-
const LATEST_RELEASE: &str = "latest";
43+
const IEDRIVER_RELEASE: &str = "IEDriverServer_Win32_";
44+
45+
thread_local!(static RELEASE_URL: RefCell<String> = RefCell::new("".to_string()));
4346

4447
pub struct IExplorerManager {
4548
pub browser_name: &'static str,
@@ -100,29 +103,75 @@ impl SeleniumManager for IExplorerManager {
100103
Ok(driver_version)
101104
}
102105
_ => {
103-
let latest_url = format!("{}{}", DRIVER_URL, LATEST_RELEASE);
104-
let driver_version = read_redirect_from_link(self.get_http_client(), latest_url)?;
105-
106-
if !browser_version.is_empty() {
107-
metadata.drivers.push(create_driver_metadata(
108-
browser_version,
109-
self.driver_name,
110-
&driver_version,
111-
));
112-
write_metadata(&metadata, self.get_logger());
106+
let selenium_releases = get_mirror_response(self.get_http_client())?;
107+
108+
let filtered_releases: Vec<SeleniumRelease> = selenium_releases
109+
.into_iter()
110+
.filter(|r| {
111+
r.assets
112+
.iter()
113+
.any(|url| url.browser_download_url.contains(IEDRIVER_RELEASE))
114+
})
115+
.collect();
116+
117+
if !filtered_releases.is_empty() {
118+
let assets = &filtered_releases.get(0).unwrap().assets;
119+
let driver_releases: Vec<&Assets> = assets
120+
.iter()
121+
.filter(|url| url.browser_download_url.contains(IEDRIVER_RELEASE))
122+
.collect();
123+
let driver_url = &driver_releases.last().unwrap().browser_download_url;
124+
RELEASE_URL.with(|url| {
125+
*url.borrow_mut() = driver_url.to_string();
126+
});
127+
128+
let index_release =
129+
driver_url.rfind(IEDRIVER_RELEASE).unwrap() + IEDRIVER_RELEASE.len();
130+
let driver_version =
131+
parse_version(driver_url.as_str()[index_release..].to_string())?;
132+
133+
if !browser_version.is_empty() {
134+
metadata.drivers.push(create_driver_metadata(
135+
browser_version,
136+
self.driver_name,
137+
&driver_version,
138+
));
139+
write_metadata(&metadata, self.get_logger());
140+
}
141+
142+
Ok(driver_version)
143+
} else {
144+
Err(format!("{} release not available", self.get_driver_name()).into())
113145
}
114-
115-
Ok(driver_version)
116146
}
117147
}
118148
}
119149

120150
fn get_driver_url(&self) -> Result<String, Box<dyn Error>> {
121-
let driver_version = self.get_driver_version();
122-
Ok(format!(
123-
"{}download/selenium-{}/IEDriverServer_Win32_{}.zip",
124-
DRIVER_URL, driver_version, driver_version
125-
))
151+
let mut driver_url = "".to_string();
152+
RELEASE_URL.with(|url| {
153+
driver_url = url.borrow().to_string();
154+
});
155+
if driver_url.is_empty() {
156+
let driver_version = self.get_driver_version();
157+
let mut release_version = driver_version.to_string();
158+
if !driver_version.ends_with('0') {
159+
// E.g.: version 4.8.1 is shipped within release 4.8.0
160+
let error_message = format!(
161+
"Wrong {} version: '{}'",
162+
self.get_driver_name(),
163+
driver_version
164+
);
165+
let index = release_version.rfind('.').ok_or(error_message)? + 1;
166+
release_version = release_version[..index].to_string();
167+
release_version.push('0');
168+
}
169+
driver_url = format!(
170+
"{}download/selenium-{}/{}{}.zip",
171+
DRIVER_URL, release_version, IEDRIVER_RELEASE, driver_version
172+
);
173+
}
174+
Ok(driver_url)
126175
}
127176

128177
fn get_driver_path_in_cache(&self) -> PathBuf {

rust/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub mod firefox;
4949
pub mod iexplorer;
5050
pub mod logger;
5151
pub mod metadata;
52+
pub mod mirror;
5253
pub mod safari;
5354
pub mod safaritp;
5455

rust/src/mirror.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
use crate::downloads::read_content_from_link;
19+
use reqwest::Client;
20+
use serde::{Deserialize, Serialize};
21+
use std::error::Error;
22+
23+
pub const MIRROR_URL: &str =
24+
"https://raw.githubusercontent.com/SeleniumHQ/selenium/trunk/common/mirror/selenium";
25+
26+
#[derive(Serialize, Deserialize)]
27+
pub struct Assets {
28+
pub browser_download_url: String,
29+
}
30+
31+
#[derive(Serialize, Deserialize)]
32+
pub struct SeleniumRelease {
33+
pub tag_name: String,
34+
pub assets: Vec<Assets>,
35+
}
36+
37+
pub fn get_mirror_response(http_client: &Client) -> Result<Vec<SeleniumRelease>, Box<dyn Error>> {
38+
let content = read_content_from_link(http_client, MIRROR_URL.to_string())?;
39+
let mirror_response: Vec<SeleniumRelease> = serde_json::from_str(&content)?;
40+
Ok(mirror_response)
41+
}

rust/tests/iexplorer_tests.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
use assert_cmd::Command;
19+
20+
use rstest::rstest;
21+
22+
#[rstest]
23+
#[case("4.8.0")]
24+
#[case("4.8.1")]
25+
fn iexplorer_test(#[case] driver_version: String) {
26+
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
27+
let cmd_assert = cmd
28+
.args([
29+
"--browser",
30+
"iexplorer",
31+
"--driver-version",
32+
&driver_version,
33+
])
34+
.assert();
35+
cmd_assert.success();
36+
}

0 commit comments

Comments
 (0)