Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/rust/src/firefox.rs
2885 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::ManagerConfig;
19
use crate::config::ARCH::{ARM64, X32};
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::{compose_driver_path_in_cache, BrowserPath};
23
use crate::metadata::{
24
create_driver_metadata, get_driver_version_from_metadata, get_metadata, write_metadata,
25
};
26
use crate::{
27
create_http_client, format_three_args, format_two_args, Logger, SeleniumManager, BETA,
28
DASH_VERSION, DEV, ESR, LATEST_RELEASE, NIGHTLY, OFFLINE_REQUEST_ERR_MSG,
29
REG_CURRENT_VERSION_ARG, STABLE,
30
};
31
use anyhow::anyhow;
32
use anyhow::Error;
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) {
402
"mac-arm64"
403
} else {
404
"mac64"
405
}
406
} else if X32.is(arch) {
407
"linux32"
408
} else if ARM64.is(arch) && minor_driver_version > 31 {
409
"linux-arm64"
410
} else {
411
"linux64"
412
}
413
}
414
415
fn request_latest_browser_version_from_online(
416
&mut self,
417
_browser_version: &str,
418
) -> Result<String, Error> {
419
let browser_name = self.browser_name;
420
self.get_logger().trace(format!(
421
"Using Firefox endpoints to find out latest stable {} version",
422
browser_name
423
));
424
425
let firefox_versions_url = self.create_firefox_details_url(FIREFOX_VERSIONS_ENDPOINT);
426
let firefox_versions =
427
parse_json_from_url::<Value>(self.get_http_client(), &firefox_versions_url)?;
428
let browser_version = firefox_versions
429
.get(FIREFOX_STABLE_LABEL)
430
.unwrap()
431
.as_str()
432
.unwrap();
433
self.set_browser_version(browser_version.to_string());
434
Ok(browser_version.to_string())
435
}
436
437
fn request_fixed_browser_version_from_online(
438
&mut self,
439
browser_version: &str,
440
) -> Result<String, Error> {
441
let browser_name = self.browser_name;
442
self.get_logger().trace(format!(
443
"Using Firefox endpoints to find out {} {}",
444
browser_name, browser_version
445
));
446
447
if self.is_unstable(browser_version) {
448
let firefox_versions_url = self.create_firefox_details_url(FIREFOX_VERSIONS_ENDPOINT);
449
let firefox_versions =
450
parse_json_from_url::<Value>(self.get_http_client(), &firefox_versions_url)?;
451
let version_label = if self.is_beta(browser_version) {
452
FIREFOX_BETA_LABEL
453
} else if self.is_dev(browser_version) {
454
FIREFOX_DEV_LABEL
455
} else if self.is_esr(browser_version) {
456
FIREFOX_ESR_LABEL
457
} else {
458
FIREFOX_CANARY_LABEL
459
};
460
let discovered_browser_version = firefox_versions
461
.get(version_label)
462
.unwrap()
463
.as_str()
464
.unwrap();
465
Ok(discovered_browser_version.to_string())
466
} else {
467
let major_browser_version = self
468
.get_major_browser_version()
469
.parse::<i32>()
470
.unwrap_or_default();
471
472
let min_downloadable_version = self.get_min_browser_version_for_download()?;
473
if major_browser_version < min_downloadable_version {
474
return Err(anyhow!(format_three_args(
475
UNAVAILABLE_DOWNLOAD_ERROR_MESSAGE,
476
browser_name,
477
browser_version,
478
&min_downloadable_version.to_string(),
479
)));
480
}
481
482
let mut firefox_versions =
483
self.request_versions_from_online(FIREFOX_HISTORY_ENDPOINT)?;
484
if firefox_versions.is_empty() {
485
firefox_versions =
486
self.request_versions_from_online(FIREFOX_HISTORY_MAJOR_ENDPOINT)?;
487
if firefox_versions.is_empty() {
488
firefox_versions =
489
self.request_versions_from_online(FIREFOX_HISTORY_DEV_ENDPOINT)?;
490
if firefox_versions.is_empty() {
491
return self.unavailable_discovery();
492
}
493
}
494
}
495
496
for version in firefox_versions.iter().rev() {
497
let release_url = format_two_args(
498
"{}{}/",
499
&self.get_browser_mirror_url_or_default(BROWSER_URL),
500
version,
501
);
502
self.get_logger()
503
.trace(format!("Checking release URL: {}", release_url));
504
let content = read_content_from_link(self.get_http_client(), &release_url)?;
505
if !content.contains("Not Found") {
506
return Ok(version.to_string());
507
}
508
}
509
self.unavailable_discovery()
510
}
511
}
512
513
fn get_min_browser_version_for_download(&self) -> Result<i32, Error> {
514
let os = self.get_os();
515
let min_browser_version_for_download = if WINDOWS.is(os) {
516
MIN_DOWNLOADABLE_FIREFOX_VERSION_WIN
517
} else if MACOS.is(os) {
518
MIN_DOWNLOADABLE_FIREFOX_VERSION_MAC
519
} else {
520
MIN_DOWNLOADABLE_FIREFOX_VERSION_LINUX
521
};
522
Ok(min_browser_version_for_download)
523
}
524
525
fn get_browser_binary_path(&mut self, browser_version: &str) -> Result<PathBuf, Error> {
526
let browser_in_cache = self.get_browser_path_in_cache()?;
527
if MACOS.is(self.get_os()) {
528
let macos_app_name = if self.is_nightly(browser_version) {
529
FIREFOX_NIGHTLY_MACOS_APP_NAME
530
} else {
531
FIREFOX_MACOS_APP_NAME
532
};
533
Ok(browser_in_cache.join(macos_app_name))
534
} else {
535
Ok(browser_in_cache.join(self.get_browser_name_with_extension()))
536
}
537
}
538
539
fn get_browser_url_for_download(&mut self, browser_version: &str) -> Result<String, Error> {
540
let arch = self.get_arch();
541
let os = self.get_os();
542
let platform_label;
543
let artifact_name;
544
let artifact_extension;
545
let major_browser_version = self
546
.get_major_browser_version()
547
.parse::<i32>()
548
.unwrap_or_default();
549
550
if WINDOWS.is(os) {
551
artifact_name = "Firefox%20Setup%20";
552
artifact_extension = "exe";
553
// Before Firefox 42, only Windows 32 was supported
554
if X32.is(arch) || major_browser_version < 42 {
555
platform_label = "win32";
556
} else if ARM64.is(arch) {
557
platform_label = "win-aarch64";
558
} else {
559
platform_label = "win64";
560
}
561
} else if MACOS.is(os) {
562
artifact_name = "Firefox%20";
563
// Before Firefox 68, only DMG was released
564
if major_browser_version < 68 {
565
artifact_extension = "dmg";
566
} else {
567
artifact_extension = "pkg";
568
}
569
if self.is_nightly(browser_version) {
570
platform_label = "osx";
571
} else {
572
platform_label = "mac";
573
}
574
} else {
575
// Linux
576
artifact_name = "firefox-";
577
if major_browser_version < 135 {
578
artifact_extension = "tar.bz2";
579
} else {
580
artifact_extension = "tar.xz";
581
}
582
if X32.is(arch) {
583
platform_label = "linux-i686";
584
} else if self.is_nightly(browser_version) {
585
if ARM64.is(arch) {
586
platform_label = "linux64-aarch64";
587
} else {
588
platform_label = "linux64";
589
}
590
} else {
591
platform_label = "linux-x86_64";
592
}
593
}
594
595
// A possible future improvement is to allow downloading language-specific releases
596
let language = FIREFOX_DEFAULT_LANG;
597
if self.is_nightly(browser_version) {
598
Ok(format_two_args(
599
FIREFOX_NIGHTLY_URL,
600
platform_label,
601
language,
602
))
603
} else {
604
let browser_version = self.get_browser_version();
605
Ok(format!(
606
"{}{}/{}/{}/{}{}.{}",
607
self.get_browser_mirror_url_or_default(BROWSER_URL),
608
browser_version,
609
platform_label,
610
language,
611
artifact_name,
612
browser_version,
613
artifact_extension
614
))
615
}
616
}
617
618
fn get_browser_label_for_download(&self, browser_version: &str) -> Result<Option<&str>, Error> {
619
let browser_label = if self.is_nightly(browser_version) {
620
FIREFOX_NIGHTLY_VOLUME
621
} else {
622
FIREFOX_VOLUME
623
};
624
Ok(Some(browser_label))
625
}
626
627
fn is_download_browser(&self) -> bool {
628
self.download_browser
629
}
630
631
fn set_download_browser(&mut self, download_browser: bool) {
632
self.download_browser = download_browser;
633
}
634
635
fn is_snap(&self, browser_path: &str) -> bool {
636
LINUX.is(self.get_os())
637
&& (browser_path.eq(FIREFOX_SNAP_LINK) || browser_path.eq(FIREFOX_SNAP_BINARY))
638
}
639
640
fn get_snap_path(&self) -> Option<PathBuf> {
641
Some(Path::new(FIREFOX_SNAP_BINARY).to_path_buf())
642
}
643
}
644
645
#[derive(Serialize, Deserialize, Debug)]
646
pub struct GeckodriverReleases {
647
#[serde(rename = "geckodriver-releases")]
648
pub geckodriver_releases: Vec<GeckodriverRelease>,
649
}
650
651
#[derive(Serialize, Deserialize, Debug)]
652
pub struct GeckodriverRelease {
653
#[serde(rename = "geckodriver-version")]
654
pub geckodriver_version: String,
655
#[serde(rename = "min-firefox-version")]
656
pub min_firefox_version: u32,
657
#[serde(rename = "max-firefox-version")]
658
pub max_firefox_version: Option<u32>,
659
}
660
661
#[cfg(test)]
662
mod unit_tests {
663
use super::*;
664
665
#[test]
666
fn test_driver_url() {
667
let mut firefox_manager = FirefoxManager::new().unwrap();
668
669
let data = vec!(
670
vec!("0.32.0", "linux", "x86", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-linux32.tar.gz"),
671
vec!("0.32.0", "linux", "x86_64", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-linux64.tar.gz"),
672
vec!("0.32.0", "linux", "aarch64", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-linux-aarch64.tar.gz"),
673
vec!("0.32.0", "windows", "x86", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-win32.zip"),
674
vec!("0.32.0", "windows", "x86_64", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-win64.zip"),
675
vec!("0.32.0", "windows", "aarch64", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-win-aarch64.zip"),
676
vec!("0.32.0", "macos", "x86", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-macos.tar.gz"),
677
vec!("0.32.0", "macos", "x86_64", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-macos.tar.gz"),
678
vec!("0.32.0", "macos", "aarch64", "https://github.com/mozilla/geckodriver/releases/download/v0.32.0/geckodriver-v0.32.0-macos-aarch64.tar.gz"),
679
vec!("0.31.0", "linux", "x86", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux32.tar.gz"),
680
vec!("0.31.0", "linux", "x86_64", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz"),
681
vec!("0.31.0", "linux", "aarch64", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz"),
682
vec!("0.31.0", "windows", "x86", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-win32.zip"),
683
vec!("0.31.0", "windows", "x86_64", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-win64.zip"),
684
vec!("0.31.0", "windows", "aarch64", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-win64.zip"),
685
vec!("0.31.0", "macos", "x86", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-macos.tar.gz"),
686
vec!("0.31.0", "macos", "x86_64", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-macos.tar.gz"),
687
vec!("0.31.0", "macos", "aarch64", "https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-macos-aarch64.tar.gz"),
688
);
689
690
data.iter().for_each(|d| {
691
firefox_manager.set_driver_version(d.first().unwrap().to_string());
692
firefox_manager.set_os(d.get(1).unwrap().to_string());
693
firefox_manager.set_arch(d.get(2).unwrap().to_string());
694
let driver_url = firefox_manager.get_driver_url().unwrap();
695
assert_eq!(d.get(3).unwrap().to_string(), driver_url);
696
});
697
}
698
}
699
700