webdriver-downloader 0.17.0

Library for webdriver download.
Documentation
use std::path::Path;

use async_trait::async_trait;
use fantoccini::wd::Capabilities;
#[cfg(target_family = "unix")]
use nix::unistd::Uid;
use regex::Regex;
use semver::{Version, VersionReq};
use serde_json::{json, Map};

use crate::os_specific;
use crate::traits::installation_info::WebdriverInstallationInfo;
use crate::traits::url_info::{UrlError, WebdriverVersionUrl};
use crate::traits::verification_info::WebdriverVerificationInfo;
use crate::traits::version_req_url_info::{VersionReqError, VersionReqUrlInfo};

use super::ChromedriverOldInfo;

#[async_trait]
impl VersionReqUrlInfo for ChromedriverOldInfo {
    fn binary_version(&self) -> Result<Version, VersionReqError> {
        os_specific::chromedriver::binary_version(&self.browser_path)
    }

    async fn driver_version_urls(&self) -> Result<Vec<WebdriverVersionUrl>, UrlError> {
        let download_xml = "https://chromedriver.storage.googleapis.com";

        let xml = reqwest::get(download_xml).await?.text().await?;

        let re = Regex::new(os_specific::chromedriver_old::ZIPFILE_NAME_RE)
            .expect("Failed to parse regex.");

        let mut versions: Vec<WebdriverVersionUrl> = vec![];
        for captures in re.captures_iter(&xml) {
            let or_else =
                || VersionReqError::RegexError(captures.get(0).unwrap().as_str().to_string());

            let version_str = captures.get(1).ok_or_else(or_else)?.as_str();
            let webdriver_version = lenient_semver::parse(version_str)
                .map_err(|e| VersionReqError::ParseVersion(e.owned()))?;

            let version_req = VersionReq::parse(&format!("^{}", webdriver_version))
                .map_err(VersionReqError::ParseVersionReq)?;

            versions.push(WebdriverVersionUrl {
                version_req,
                webdriver_version,
                url: os_specific::chromedriver_old::build_url(version_str),
            });
        }

        Ok(versions)
    }
}

impl WebdriverInstallationInfo for ChromedriverOldInfo {
    fn driver_install_path(&self) -> &Path {
        &self.driver_install_path
    }

    fn driver_executable_name(&self) -> &'static str {
        os_specific::chromedriver::DRIVER_EXECUTABLE_NAME
    }
}

impl WebdriverVerificationInfo for ChromedriverOldInfo {
    fn driver_capabilities(&self) -> Option<Capabilities> {
        #[cfg(target_family = "unix")]
        let args = match Uid::effective().is_root() {
            true => vec!["--no-sandbox", "-headless"],
            false => vec!["-headless"],
        };
        #[cfg(not(target_family = "unix"))]
        let args = vec!["-headless"];

        let capabilities_value = json!({
            "binary": self.browser_path,
            "args": args,
        });

        let mut capabilities = Map::new();

        capabilities.insert("goog:chromeOptions".to_string(), capabilities_value);

        Some(capabilities)
    }
}

#[cfg(test)]
mod tests {
    use anyhow::Result;
    use test_log::test;

    use crate::prelude::*;

    use super::ChromedriverOldInfo;

    #[test]
    fn test_get_binary_version() -> Result<()> {
        let browser_path = os_specific::chromedriver_old::default_browser_path()
            .expect("Failed to get default browser path");

        let chromedriver_info = ChromedriverOldInfo {
            driver_install_path: "".into(),
            browser_path,
        };

        chromedriver_info.binary_version()?;

        Ok(())
    }
}