Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firefox is set but using chrome #1

Closed
makorne opened this issue Oct 2, 2021 · 4 comments
Closed

Firefox is set but using chrome #1

makorne opened this issue Oct 2, 2021 · 4 comments

Comments

@makorne
Copy link

makorne commented Oct 2, 2021

Testing untrusted certs with WebGrid Docker:

use anyhow::{bail, Result};
use humantime::format_duration;
use std::{
    collections::HashMap,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
    time::{Duration, Instant},
};
use thirtyfour::{prelude::*, Capabilities, ExtensionCommand};
use thirtyfour::common::capabilities::firefox::FirefoxPreferences;
use tokio::{spawn, time::sleep};

struct WebgridMetadataCommand {
    fields: HashMap<String, String>,
}

impl WebgridMetadataCommand {
    pub fn new() -> Self {
        Self {
            fields: HashMap::new(),
        }
    }

    pub fn with_field(key: String, value: String) -> Self {
        let mut instance = Self::new();
        instance.add(key, value);
        instance
    }

    pub fn add(&mut self, key: String, value: String) {
        self.fields.insert(key, value);
    }
}

impl ExtensionCommand for WebgridMetadataCommand {
    fn parameters_json(&self) -> Option<serde_json::Value> {
        serde_json::to_value(self.fields.clone()).ok()
    }

    fn method(&self) -> thirtyfour::RequestMethod {
        thirtyfour::RequestMethod::Post
    }

    fn endpoint(&self) -> String {
        "/webgrid/metadata".into()
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    pretty_env_logger::formatted_timed_builder()
        .filter_level(log::LevelFilter::Info)
        .init();

    let args: Vec<String> = std::env::args().collect();

    let endpoint = &args[1];
    let count = args[2].parse::<u64>().unwrap();
    let browser = if args.len() > 3 {
        args[3].to_ascii_lowercase()
    } else {
        "firefox".to_owned()
    };

    let timeout_secs = std::env::var("TIMEOUT")
        .unwrap_or("600".into())
        .parse::<u64>()
        .expect("Failed to parse timeout!");
    let timeout = Some(Duration::from_secs(timeout_secs));

    log::info!("Running {} tests against '{}'", count, endpoint);

    let mut handles = Vec::new();

    let failed = Arc::new(AtomicU64::new(0));

    for id in 0..count {
        let failed = failed.clone();
        let endpoint = endpoint.clone();
        let browser = browser.clone();
        let handle = spawn(async move {
            // Wait a tiny bit to stagger the requests
            sleep(Duration::from_millis(id * 25)).await;

            // Run the test
            let start = Instant::now();
            let result = run_test_untrusted_certs(&endpoint.clone(), &browser.clone(), timeout.clone()).await;
            let duration = Instant::now() - start;

            // Report the result (and duration)
            match result {
                Ok(_) => {
                    log::info!("Test #{} finished in {}.", id, format_duration(duration));
                    Ok(())
                }
                Err(e) => {
                    log::info!("Test #{} failed: {}", id, e);
                    failed.fetch_add(1, Ordering::Relaxed);
                    Err(e)
                }
            }
        });
        handles.push(handle);
    }

    for handle in handles.into_iter() {
        handle.await?.ok();
    }

    let failed = failed.load(Ordering::SeqCst);

    log::info!(
        "All tests finished. {} / {} succeeded.",
        count - failed,
        count
    );

    if failed > 0 {
        std::process::exit(1);
    }

    Ok(())
}

async fn run_test_untrusted_certs(endpoint: &str, browser: &str, timeout: Option<Duration>) -> Result<()> {
    let mut metadata = HashMap::new();
    metadata.insert("name", "test-name");
    metadata.insert("build", "test-build");

    let mut driver = if browser == "firefox" {
        let mut caps = DesiredCapabilities::firefox();
        let mut preferences = FirefoxPreferences::default();
        preferences.set_accept_untrusted_certs(true)?;
        caps.set_preferences(preferences)?;
        caps.add_subkey("webgrid:options", "metadata", metadata)?;
        WebDriver::new_with_timeout(endpoint, &caps, timeout).await?

    } else if browser == "chrome" {
        let mut caps = DesiredCapabilities::chrome();
        caps.add_subkey("webgrid:options", "metadata", metadata)?;
        caps.add_chrome_arg("ignore-certificate-errors")?;
        WebDriver::new_with_timeout(endpoint, &caps, timeout).await?

    } else if browser == "safari" {
        let mut caps = DesiredCapabilities::safari();
        caps.add_subkey("webgrid:options", "metadata", metadata)?;
        WebDriver::new_with_timeout(endpoint, &caps, timeout).await?
    } else {
        bail!("Unknown browser!");
    };

    let session_id = driver.session_id().to_string();

    if let Err(e) =  run_test_content_untrusted_certs(&mut driver).await {
        driver.quit().await.ok();
        bail!("{} failed due to {}", session_id, e);
    } else {
        driver.quit().await.ok();
    }

    Ok(())
}

async fn run_test_content_untrusted_certs(driver: &mut WebDriver) -> Result<()> {
    send_message(&driver, "Visiting cacert.org page").await?;
    driver.get( "https://cacert.org/").await?;
    send_message(&driver, "It worked!").await?;
    set_status(&driver, "success").await?;
    Ok(())
}

async fn send_message(driver: &WebDriver, message: &str) -> Result<()> {
    let cookie = Cookie::new("webgrid:message", serde_json::json!(message));
    driver.add_cookie(cookie).await.ok();
    Ok(())
}

async fn set_status(driver: &WebDriver, status: &str) -> Result<()> {
    let cookie = Cookie::new("webgrid:metadata.session:status", serde_json::json!(status));
    driver.add_cookie(cookie).await.ok();

    Ok(())
}

Result:

`target/debug/basic-test 'http://localhost:8080/' 1 firefox`
 2021-10-02T08:00:54.566Z INFO  basic_test > browser firefox
 2021-10-02T08:00:54.566Z INFO  basic_test > Running 1 tests against 'http://localhost:8080/'
 2021-10-02T08:01:01.638Z INFO  basic_test > Test #0 failed: 6d5bd891-22a9-49f9-85c5-8cc492a5ae27 failed due to The certificate is insecure:     
    Status: 400
    Additional info:
        Error: insecure certificate
        Stacktrace:
            WebDriverError@chrome://marionette/content/error.js:175:5
            InsecureCertificateError@chrome://marionette/content/error.js:296:5
            handleReadyState@chrome://marionette/content/listener.js:292:21
            handleEvent@chrome://marionette/content/listener.js:263:14
            
 2021-10-02T08:01:01.639Z INFO  basic_test > All tests finished. 0 / 1 succeeded.
@TilBlechschmidt
Copy link
Owner

Could you please provide the whole source code file? It would help with gaining some context 🙂

@makorne
Copy link
Author

makorne commented Oct 2, 2021

Ready!

@TilBlechschmidt
Copy link
Owner

I managed to reproduce the insecure-certificate error. Regarding the certificates, that seems to be an error on behalf of the thirtyfour library used here. According to the documentation of Firefox, one has to set the acceptInsecureCerts key in the capabilities object to true. This seemingly also works with Chrome as long as it is sufficiently recent — which it should be in this case. To set this capability, you can use this little code snippet:

caps.add("acceptInsecureCerts", true)?;

Which results in a more complete example like this:

let mut caps = DesiredCapabilities::firefox();
caps.add("acceptInsecureCerts", true)?;
caps.add_subkey("webgrid:options", "metadata", metadata)?;
WebDriver::new_with_timeout(endpoint, &caps, timeout).await?

Regarding the FF vs. Chrome situation: The log output reads WebDriverError@chrome://marionette. However, the word chrome in there references the "window chrome" of the Firefox browser, not the browser Google Chrome. A tad confusing but if you check the docker ps output and/or the logs of the session container while the browser is running, it is most definitely the Firefox image being used.

@TilBlechschmidt
Copy link
Owner

TilBlechschmidt commented Oct 2, 2021

If you want, you can open up an issue with the thirtyfour project to add this as a function on the DesiredCapabilities object. I'm sure @stevepryde would appreciate the suggestion 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants