Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rust/src/firefox.rs
3994 views
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::config::ARCH::{ARM64, X32};
19
use crate::config::ManagerConfig;
20
use crate::config::OS::{LINUX, MACOS, WINDOWS};
21
use crate::downloads::{parse_json_from_url, read_content_from_link, read_redirect_from_link};
22
use crate::files::{BrowserPath, compose_driver_path_in_cache};
23
use crate::metadata::{
24
create_driver_metadata, get_driver_version_from_metadata, get_metadata, write_metadata,
25
};
26
use crate::{
27
BETA, DASH_VERSION, DEV, ESR, LATEST_RELEASE, Logger, NIGHTLY, OFFLINE_REQUEST_ERR_MSG,
28
REG_CURRENT_VERSION_ARG, STABLE, SeleniumManager, create_http_client, format_three_args,
29
format_two_args,
30
};
31
use anyhow::Error;
32
use anyhow::anyhow;
33
use reqwest::Client;
34
use serde::Deserialize;
35
use serde::Serialize;
36
use serde_json::Value;
37
use std::collections::HashMap;
38
use std::path::{Path, PathBuf};
39
use std::sync::mpsc;
40
use std::sync::mpsc::{Receiver, Sender};
41
42
pub const FIREFOX_NAME: &str = "firefox";
43
pub const GECKODRIVER_NAME: &str = "geckodriver";
44
const DRIVER_URL: &str = "https://github.com/mozilla/geckodriver/releases/";
45
const DRIVER_VERSIONS_URL: &str = "https://raw.githubusercontent.com/SeleniumHQ/selenium/trunk/common/geckodriver/geckodriver-support.json";
46
const BROWSER_URL: &str = "https://ftp.mozilla.org/pub/firefox/releases/";
47
const FIREFOX_DEFAULT_LANG: &str = "en-US";
48
const FIREFOX_MACOS_APP_NAME: &str = "Firefox.app/Contents/MacOS/firefox";
49
const FIREFOX_NIGHTLY_MACOS_APP_NAME: &str = "Firefox Nightly.app/Contents/MacOS/firefox";
50
const FIREFOX_DETAILS_URL: &str = "https://product-details.mozilla.org/1.0/";
51
const FIREFOX_STABLE_LABEL: &str = "LATEST_FIREFOX_VERSION";
52
const FIREFOX_BETA_LABEL: &str = "LATEST_FIREFOX_RELEASED_DEVEL_VERSION";
53
const FIREFOX_DEV_LABEL: &str = "FIREFOX_DEVEDITION";
54
const FIREFOX_CANARY_LABEL: &str = "FIREFOX_NIGHTLY";
55
const FIREFOX_ESR_LABEL: &str = "FIREFOX_ESR";
56
const FIREFOX_VERSIONS_ENDPOINT: &str = "firefox_versions.json";
57
const FIREFOX_HISTORY_ENDPOINT: &str = "firefox_history_stability_releases.json";
58
const FIREFOX_HISTORY_MAJOR_ENDPOINT: &str = "firefox_history_major_releases.json";
59
const FIREFOX_HISTORY_DEV_ENDPOINT: &str = "firefox_history_development_releases.json";
60
const FIREFOX_NIGHTLY_URL: &str =
61
"https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os={}&lang={}";
62
const FIREFOX_VOLUME: &str = "Firefox";
63
const FIREFOX_NIGHTLY_VOLUME: &str = r"Firefox\ Nightly";
64
const MIN_DOWNLOADABLE_FIREFOX_VERSION_WIN: i32 = 13;
65
const MIN_DOWNLOADABLE_FIREFOX_VERSION_MAC: i32 = 4;
66
const MIN_DOWNLOADABLE_FIREFOX_VERSION_LINUX: i32 = 4;
67
const UNAVAILABLE_DOWNLOAD_ERROR_MESSAGE: &str =
68
"{} {} not available for downloading (minimum version: {})";
69
const FIREFOX_SNAP_LINK: &str = "/snap/bin/firefox";
70
const FIREFOX_SNAP_BINARY: &str = "/snap/firefox/current/usr/lib/firefox/firefox";
71
72
pub struct FirefoxManager {
73
pub browser_name: &'static str,
74
pub driver_name: &'static str,
75
pub config: ManagerConfig,
76
pub http_client: Client,
77
pub log: Logger,
78
pub tx: Sender<String>,
79
pub rx: Receiver<String>,
80
pub download_browser: bool,
81
}
82
83
impl FirefoxManager {
84
pub fn new() -> Result<Box<Self>, Error> {
85
let browser_name = FIREFOX_NAME;
86
let driver_name = GECKODRIVER_NAME;
87
let config = ManagerConfig::default(browser_name, driver_name);
88
let default_timeout = config.timeout.to_owned();
89
let default_proxy = &config.proxy;
90
let (tx, rx): (Sender<String>, Receiver<String>) = mpsc::channel();
91
Ok(Box::new(FirefoxManager {
92
browser_name,
93
driver_name,
94
http_client: create_http_client(default_timeout, default_proxy)?,
95
config,
96
log: Logger::new(),
97
tx,
98
rx,
99
download_browser: false,
100
}))
101
}
102
103
fn create_firefox_details_url(&self, endpoint: &str) -> String {
104
format!("{}{}", FIREFOX_DETAILS_URL, endpoint)
105
}
106
107
fn request_versions_from_online(&mut self, endpoint: &str) -> Result<Vec<String>, Error> {
108
let browser_version = self.get_browser_version().to_string();
109
let firefox_versions_url = self.create_firefox_details_url(endpoint);
110
let firefox_versions =
111
parse_json_from_url::<Value>(self.get_http_client(), &firefox_versions_url)?;
112
113
let versions_map = firefox_versions.as_object().unwrap();
114
let filter_key = if browser_version.contains('.') {
115
browser_version
116
} else {
117
format!("{}.", browser_version)
118
};
119
Ok(versions_map
120
.keys()
121
.filter(|v| v.starts_with(&filter_key))
122
.map(|v| v.to_string())
123
.collect())
124
}
125
}
126
127
impl SeleniumManager for FirefoxManager {
128
fn get_browser_name(&self) -> &str {
129
self.browser_name
130
}
131
132
fn get_browser_names_in_path(&self) -> Vec<&str> {
133
vec![self.get_browser_name()]
134
}
135
136
fn get_http_client(&self) -> &Client {
137
&self.http_client
138
}
139
140
fn set_http_client(&mut self, http_client: Client) {
141
self.http_client = http_client;
142
}
143
144
fn get_browser_path_map(&self) -> HashMap<BrowserPath, &str> {
145
HashMap::from([
146
(
147
BrowserPath::new(WINDOWS, STABLE),
148
r"Mozilla Firefox\firefox.exe",
149
),
150
(
151
BrowserPath::new(WINDOWS, BETA),
152
// "",
153
r"Mozilla Firefox\firefox.exe",
154
),
155
(
156
BrowserPath::new(WINDOWS, DEV),
157
r"Firefox Developer Edition\firefox.exe",
158
),
159
(
160
BrowserPath::new(WINDOWS, NIGHTLY),
161
r"Firefox Nightly\firefox.exe",
162
),
163
(
164
BrowserPath::new(WINDOWS, ESR),
165
r"Mozilla Firefox\firefox.exe",
166
),
167
(
168
BrowserPath::new(MACOS, STABLE),
169
"/Applications/Firefox.app/Contents/MacOS/firefox",
170
),
171
(
172
BrowserPath::new(MACOS, BETA),
173
"/Applications/Firefox.app/Contents/MacOS/firefox",
174
),
175
(
176
BrowserPath::new(MACOS, DEV),
177
"/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox",
178
),
179
(
180
BrowserPath::new(MACOS, NIGHTLY),
181
"/Applications/Firefox Nightly.app/Contents/MacOS/firefox",
182
),
183
(
184
BrowserPath::new(MACOS, ESR),
185
"/Applications/Firefox.app/Contents/MacOS/firefox",
186
),
187
(BrowserPath::new(LINUX, STABLE), "/usr/bin/firefox"),
188
(BrowserPath::new(LINUX, BETA), "/usr/bin/firefox"),
189
(BrowserPath::new(LINUX, DEV), "/usr/bin/firefox"),
190
(BrowserPath::new(LINUX, NIGHTLY), "/usr/bin/firefox-trunk"),
191
(BrowserPath::new(LINUX, ESR), "/usr/bin/firefox"),
192
])
193
}
194
195
fn discover_browser_version(&mut self) -> Result<Option<String>, Error> {
196
self.general_discover_browser_version(
197
r"HKCU\Software\Mozilla\Mozilla Firefox",
198
REG_CURRENT_VERSION_ARG,
199
DASH_VERSION,
200
)
201
}
202
203
fn get_driver_name(&self) -> &str {
204
self.driver_name
205
}
206
207
fn request_driver_version(&mut self) -> Result<String, Error> {
208
let major_browser_version_binding = self.get_major_browser_version();
209
let major_browser_version = major_browser_version_binding.as_str();
210
let cache_path = self.get_cache_path()?;
211
let mut metadata = get_metadata(self.get_logger(), &cache_path);
212
213
match get_driver_version_from_metadata(
214
&metadata.drivers,
215
self.driver_name,
216
major_browser_version,
217
) {
218
Some(driver_version) => {
219
self.log.trace(format!(
220
"Driver TTL is valid. Getting {} version from metadata",
221
&self.driver_name
222
));
223
Ok(driver_version)
224
}
225
_ => {
226
self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?;
227
228
let driver_version_url =
229
self.get_driver_mirror_versions_url_or_default(DRIVER_VERSIONS_URL);
230
let driver_version = match parse_json_from_url::<GeckodriverReleases>(
231
self.get_http_client(),
232
&driver_version_url,
233
) {
234
Ok(driver_releases) => {
235
let major_browser_version_int =
236
major_browser_version.parse::<u32>().unwrap_or_default();
237
let filtered_versions: Vec<String> = driver_releases
238
.geckodriver_releases
239
.into_iter()
240
.filter(|r| {
241
major_browser_version_int >= r.min_firefox_version
242
&& (r.max_firefox_version.is_none()
243
|| (r.max_firefox_version.is_some()
244
&& major_browser_version_int
245
<= r.max_firefox_version.unwrap()))
246
})
247
.map(|r| r.geckodriver_version)
248
.collect();
249
self.log.debug(format!(
250
"Valid {} versions for {} {}: {:?}",
251
&self.driver_name,
252
&self.browser_name,
253
major_browser_version_int,
254
filtered_versions
255
));
256
if filtered_versions.is_empty() {
257
return Err(anyhow!(format!(
258
"Not valid {} version found for {} {}",
259
&self.driver_name, &self.browser_name, major_browser_version_int
260
)));
261
} else {
262
filtered_versions.first().unwrap().to_string()
263
}
264
}
265
Err(err) => {
266
self.log.warn(format!(
267
"Problem reading {} versions: {}. Using latest {} version",
268
&self.driver_name, err, &self.driver_name,
269
));
270
let latest_url = format!(
271
"{}{}",
272
self.get_driver_mirror_url_or_default(DRIVER_URL),
273
LATEST_RELEASE
274
);
275
read_redirect_from_link(
276
self.get_http_client(),
277
latest_url,
278
self.get_logger(),
279
)?
280
}
281
};
282
283
let driver_ttl = self.get_ttl();
284
if driver_ttl > 0 && !major_browser_version.is_empty() {
285
metadata.drivers.push(create_driver_metadata(
286
major_browser_version,
287
self.driver_name,
288
&driver_version,
289
driver_ttl,
290
));
291
write_metadata(&metadata, self.get_logger(), cache_path);
292
}
293
294
Ok(driver_version)
295
}
296
}
297
}
298
299
fn request_browser_version(&mut self) -> Result<Option<String>, Error> {
300
self.general_request_browser_version(self.browser_name)
301
}
302
303
fn get_driver_url(&mut self) -> Result<String, Error> {
304
let driver_version = self.get_driver_version();
305
let os = self.get_os();
306
let arch = self.get_arch();
307
308
// As of 0.32.0, geckodriver ships aarch64 binaries for Linux and Windows
309
// https://github.com/mozilla/geckodriver/releases/tag/v0.32.0
310
let minor_driver_version = self
311
.get_minor_version(driver_version)?
312
.parse::<i32>()
313
.unwrap_or_default();
314
let driver_label = if WINDOWS.is(os) {
315
if X32.is(arch) {
316
"win32.zip"
317
} else if ARM64.is(arch) && minor_driver_version > 31 {
318
"win-aarch64.zip"
319
} else {
320
"win64.zip"
321
}
322
} else if MACOS.is(os) {
323
if ARM64.is(arch) {
324
"macos-aarch64.tar.gz"
325
} else {
326
"macos.tar.gz"
327
}
328
} else if X32.is(arch) {
329
"linux32.tar.gz"
330
} else if ARM64.is(arch) && minor_driver_version > 31 {
331
"linux-aarch64.tar.gz"
332
} else {
333
"linux64.tar.gz"
334
};
335
Ok(format!(
336
"{}download/v{}/{}-v{}-{}",
337
self.get_driver_mirror_url_or_default(DRIVER_URL),
338
driver_version,
339
self.driver_name,
340
driver_version,
341
driver_label
342
))
343
}
344
345
fn get_driver_path_in_cache(&self) -> Result<PathBuf, Error> {
346
Ok(compose_driver_path_in_cache(
347
self.get_cache_path()?.unwrap_or_default(),
348
self.driver_name,
349
self.get_os(),
350
self.get_platform_label(),
351
self.get_driver_version(),
352
))
353
}
354
355
fn get_config(&self) -> &ManagerConfig {
356
&self.config
357
}
358
359
fn get_config_mut(&mut self) -> &mut ManagerConfig {
360
&mut self.config
361
}
362
363
fn set_config(&mut self, config: ManagerConfig) {
364
self.config = config;
365
}
366
367
fn get_logger(&self) -> &Logger {
368
&self.log
369
}
370
371
fn set_logger(&mut self, log: Logger) {
372
self.log = log;
373
}
374
375
fn get_sender(&self) -> &Sender<String> {
376
&self.tx
377
}
378
379
fn get_receiver(&self) -> &Receiver<String> {
380
&self.rx
381
}
382
383
fn get_platform_label(&self) -> &str {
384
let driver_version = self.get_driver_version();
385
let os = self.get_os();
386
let arch = self.get_arch();
387
let minor_driver_version = self
388
.get_minor_version(driver_version)
389
.unwrap_or_default()
390
.parse::<i32>()
391
.unwrap_or_default();
392
if WINDOWS.is(os) {
393
if X32.is(arch) {
394
"win32"
395
} else if ARM64.is(arch) && minor_driver_version > 31 {
396
"win-arm64"
397
} else {
398
"win64"
399
}
400
} else if MACOS.is(os) {
401
if ARM64.is(arch) { "mac-arm64" } else { "mac64" }
402
} else if X32.is(arch) {
403
"linux32"
404
} else if ARM64.is(arch) && minor_driver_version > 31 {
405
"linux-arm64"
406
} else {
407
"linux64"
408
}
409
}
410
411
fn request_latest_browser_version_from_online(
412
&mut self,
413
_browser_version: &str,
414
) -> Result<String, Error> {
415
let browser_name = self.browser_name;
416
self.get_logger().trace(format!(
417
"Using Firefox endpoints to find out latest stable {} version",
418
browser_name
419
));
420
421
let firefox_versions_url = self.create_firefox_details_url(FIREFOX_VERSIONS_ENDPOINT);
422
let firefox_versions =
423
parse_json_from_url::<Value>(self.get_http_client(), &firefox_versions_url)?;
424
let browser_version = firefox_versions
425
.get(FIREFOX_STABLE_LABEL)
426
.unwrap()
427
.as_str()
428
.unwrap();
429
self.set_browser_version(browser_version.to_string());
430
Ok(browser_version.to_string())
431
}
432
433
fn request_fixed_browser_version_from_online(
434
&mut self,
435
browser_version: &str,
436
) -> Result<String, Error> {
437
let browser_name = self.browser_name;
438
self.get_logger().trace(format!(
439
"Using Firefox endpoints to find out {} {}",
440
browser_name, browser_version
441
));
442
443
if self.is_unstable(browser_version) {
444
let firefox_versions_url = self.create_firefox_details_url(FIREFOX_VERSIONS_ENDPOINT);
445
let firefox_versions =
446
parse_json_from_url::<Value>(self.get_http_client(), &firefox_versions_url)?;
447
let version_label = if self.is_beta(browser_version) {
448
FIREFOX_BETA_LABEL
449
} else if self.is_dev(browser_version) {
450
FIREFOX_DEV_LABEL
451
} else if self.is_esr(browser_version) {
452
FIREFOX_ESR_LABEL
453
} else {
454
FIREFOX_CANARY_LABEL
455
};
456
let discovered_browser_version = firefox_versions
457
.get(version_label)
458
.unwrap()
459
.as_str()
460
.unwrap();
461
Ok(discovered_browser_version.to_string())
462
} else {
463
let major_browser_version = self
464
.get_major_browser_version()
465
.parse::<i32>()
466
.unwrap_or_default();
467
468
let min_downloadable_version = self.get_min_browser_version_for_download()?;
469
if major_browser_version < min_downloadable_version {
470
return Err(anyhow!(format_three_args(
471
UNAVAILABLE_DOWNLOAD_ERROR_MESSAGE,
472
browser_name,
473
browser_version,
474
&min_downloadable_version.to_string(),
475
)));
476
}
477
478
let mut firefox_versions =
479
self.request_versions_from_online(FIREFOX_HISTORY_ENDPOINT)?;
480
if firefox_versions.is_empty() {
481
firefox_versions =
482
self.request_versions_from_online(FIREFOX_HISTORY_MAJOR_ENDPOINT)?;
483
if firefox_versions.is_empty() {
484
firefox_versions =
485
self.request_versions_from_online(FIREFOX_HISTORY_DEV_ENDPOINT)?;
486
if firefox_versions.is_empty() {
487
return self.unavailable_discovery();
488
}
489
}
490
}
491
492
for version in firefox_versions.iter().rev() {
493
let release_url = format_two_args(
494
"{}{}/",
495
&self.get_browser_mirror_url_or_default(BROWSER_URL),
496
version,
497
);
498
self.get_logger()
499
.trace(format!("Checking release URL: {}", release_url));
500
let content = read_content_from_link(self.get_http_client(), &release_url)?;
501
if !content.contains("Not Found") {
502
return Ok(version.to_string());
503
}
504
}
505
self.unavailable_discovery()
506
}
507
}
508
509
fn get_min_browser_version_for_download(&self) -> Result<i32, Error> {
510
let os = self.get_os();
511
let min_browser_version_for_download = if WINDOWS.is(os) {
512
MIN_DOWNLOADABLE_FIREFOX_VERSION_WIN
513
} else if MACOS.is(os) {
514
MIN_DOWNLOADABLE_FIREFOX_VERSION_MAC
515
} else {
516
MIN_DOWNLOADABLE_FIREFOX_VERSION_LINUX
517
};
518
Ok(min_browser_version_for_download)
519
}
520
521
fn get_browser_binary_path(&mut self, browser_version: &str) -> Result<PathBuf, Error> {
522
let browser_in_cache = self.get_browser_path_in_cache()?;
523
if MACOS.is(self.get_os()) {
524
let macos_app_name = if self.is_nightly(browser_version) {
525
FIREFOX_NIGHTLY_MACOS_APP_NAME
526
} else {
527
FIREFOX_MACOS_APP_NAME
528
};
529
Ok(browser_in_cache.join(macos_app_name))
530
} else {
531
Ok(browser_in_cache.join(self.get_browser_name_with_extension()))
532
}
533
}
534
535
fn get_browser_url_for_download(&mut self, browser_version: &str) -> Result<String, Error> {
536
let arch = self.get_arch();
537
let os = self.get_os();
538
let platform_label;
539
let artifact_name;
540
let artifact_extension;
541
let major_browser_version = self
542
.get_major_browser_version()
543
.parse::<i32>()
544
.unwrap_or_default();
545
546
if WINDOWS.is(os) {
547
artifact_name = "Firefox%20Setup%20";
548
artifact_extension = "exe";
549
// Before Firefox 42, only Windows 32 was supported
550
if X32.is(arch) || major_browser_version < 42 {
551
platform_label = "win32";
552
} else if ARM64.is(arch) {
553
platform_label = "win-aarch64";
554
} else {
555
platform_label = "win64";
556
}
557
} else if MACOS.is(os) {
558
artifact_name = "Firefox%20";
559
// Before Firefox 68, only DMG was released
560
if major_browser_version < 68 {
561
artifact_extension = "dmg";
562
} else {
563
artifact_extension = "pkg";
564
}
565
if self.is_nightly(browser_version) {
566
platform_label = "osx";
567
} else {
568
platform_label = "mac";
569
}
570
} else {
571
// Linux
572
artifact_name = "firefox-";
573
if major_browser_version < 135 {
574
artifact_extension = "tar.bz2";
575
} else {
576
artifact_extension = "tar.xz";
577
}
578
if X32.is(arch) {
579
platform_label = "linux-i686";
580
} else if self.is_nightly(browser_version) {
581
if ARM64.is(arch) {
582
platform_label = "linux64-aarch64";
583
} else {
584
platform_label = "linux64";
585
}
586
} else {
587
platform_label = "linux-x86_64";
588
}
589
}
590
591
// A possible future improvement is to allow downloading language-specific releases
592
let language = FIREFOX_DEFAULT_LANG;
593
if self.is_nightly(browser_version) {
594
Ok(format_two_args(
595
FIREFOX_NIGHTLY_URL,
596
platform_label,
597
language,
598
))
599
} else {
600
let browser_version = self.get_browser_version();
601
Ok(format!(
602
"{}{}/{}/{}/{}{}.{}",
603
self.get_browser_mirror_url_or_default(BROWSER_URL),
604
browser_version,
605
platform_label,
606
language,
607
artifact_name,
608
browser_version,
609
artifact_extension
610
))
611
}
612
}
613
614
fn get_browser_label_for_download(&self, browser_version: &str) -> Result<Option<&str>, Error> {
615
let browser_label = if self.is_nightly(browser_version) {
616
FIREFOX_NIGHTLY_VOLUME
617
} else {
618
FIREFOX_VOLUME
619
};
620
Ok(Some(browser_label))
621
}
622
623
fn is_download_browser(&self) -> bool {
624
self.download_browser
625
}
626
627
fn set_download_browser(&mut self, download_browser: bool) {
628
self.download_browser = download_browser;
629
}
630
631
fn is_snap(&self, browser_path: &str) -> bool {
632
LINUX.is(self.get_os())
633
&& (browser_path.eq(FIREFOX_SNAP_LINK) || browser_path.eq(FIREFOX_SNAP_BINARY))
634
}
635
636
fn get_snap_path(&self) -> Option<PathBuf> {
637
Some(Path::new(FIREFOX_SNAP_BINARY).to_path_buf())
638
}
639
}
640
641
#[derive(Serialize, Deserialize, Debug)]
642
pub struct GeckodriverReleases {
643
#[serde(rename = "geckodriver-releases")]
644
pub geckodriver_releases: Vec<GeckodriverRelease>,
645
}
646
647
#[derive(Serialize, Deserialize, Debug)]
648
pub struct GeckodriverRelease {
649
#[serde(rename = "geckodriver-version")]
650
pub geckodriver_version: String,
651
#[serde(rename = "min-firefox-version")]
652
pub min_firefox_version: u32,
653
#[serde(rename = "max-firefox-version")]
654
pub max_firefox_version: Option<u32>,
655
}
656
657
#[cfg(test)]
658
mod unit_tests {
659
use super::*;
660
661
#[test]
662
fn test_driver_url() {
663
let mut firefox_manager = FirefoxManager::new().unwrap();
664
665
let data = vec![
666
vec![
667
"0.32.0",
668
"linux",
669
"x86",
670
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-linux32.tar.gz",
671
],
672
vec![
673
"0.32.0",
674
"linux",
675
"x86_64",
676
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-linux64.tar.gz",
677
],
678
vec![
679
"0.32.0",
680
"linux",
681
"aarch64",
682
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-linux-aarch64.tar.gz",
683
],
684
vec![
685
"0.32.0",
686
"windows",
687
"x86",
688
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-win32.zip",
689
],
690
vec![
691
"0.32.0",
692
"windows",
693
"x86_64",
694
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-win64.zip",
695
],
696
vec![
697
"0.32.0",
698
"windows",
699
"aarch64",
700
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-win-aarch64.zip",
701
],
702
vec![
703
"0.32.0",
704
"macos",
705
"x86",
706
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-macos.tar.gz",
707
],
708
vec![
709
"0.32.0",
710
"macos",
711
"x86_64",
712
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-macos.tar.gz",
713
],
714
vec![
715
"0.32.0",
716
"macos",
717
"aarch64",
718
"https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-macos-aarch64.tar.gz",
719
],
720
vec![
721
"0.31.0",
722
"linux",
723
"x86",
724
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux32.tar.gz",
725
],
726
vec![
727
"0.31.0",
728
"linux",
729
"x86_64",
730
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz",
731
],
732
vec![
733
"0.31.0",
734
"linux",
735
"aarch64",
736
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz",
737
],
738
vec![
739
"0.31.0",
740
"windows",
741
"x86",
742
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-win32.zip",
743
],
744
vec![
745
"0.31.0",
746
"windows",
747
"x86_64",
748
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-win64.zip",
749
],
750
vec![
751
"0.31.0",
752
"windows",
753
"aarch64",
754
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-win64.zip",
755
],
756
vec![
757
"0.31.0",
758
"macos",
759
"x86",
760
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-macos.tar.gz",
761
],
762
vec![
763
"0.31.0",
764
"macos",
765
"x86_64",
766
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-macos.tar.gz",
767
],
768
vec![
769
"0.31.0",
770
"macos",
771
"aarch64",
772
"https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-macos-aarch64.tar.gz",
773
],
774
];
775
776
data.iter().for_each(|d| {
777
firefox_manager.set_driver_version(d.first().unwrap().to_string());
778
firefox_manager.set_os(d.get(1).unwrap().to_string());
779
firefox_manager.set_arch(d.get(2).unwrap().to_string());
780
let driver_url = firefox_manager.get_driver_url().unwrap();
781
assert_eq!(d.get(3).unwrap().to_string(), driver_url);
782
});
783
}
784
}
785
786