#![allow(dead_code, unused_imports)]
pub mod server;
pub use server::*;
use std::sync::{Arc, OnceLock};
use std::time::Duration;
use tokio::sync::{Mutex, OwnedMutexGuard};
use earl_core::schema::ResultTemplate;
use earl_core::transport::ResolvedTransport;
use earl_core::{CommandMode, ExecutionContext, ProtocolExecutor, Redactor};
use earl_protocol_browser::{BrowserExecutor, PreparedBrowserCommand};
use serde_json::{Map, Value};
pub struct ChromeGuard {
_mutex_guard: OwnedMutexGuard<()>,
_file: std::fs::File,
}
impl Drop for ChromeGuard {
fn drop(&mut self) {
use fs4::FileExt;
let _ = self._file.unlock();
}
}
pub async fn chrome_lock() -> ChromeGuard {
static PROCESS_MUTEX: OnceLock<Arc<Mutex<()>>> = OnceLock::new();
let mutex = PROCESS_MUTEX
.get_or_init(|| Arc::new(Mutex::new(())))
.clone();
let mutex_guard = mutex.lock_owned().await;
let lock_path = std::env::temp_dir().join("earl_browser_tests.lock");
let file = tokio::task::spawn_blocking(move || -> std::io::Result<std::fs::File> {
use fs4::FileExt;
let f = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(&lock_path)?;
f.lock()?;
Ok(f)
})
.await
.expect("spawn_blocking panicked")
.expect("failed to acquire file lock for Chrome tests");
ChromeGuard {
_mutex_guard: mutex_guard,
_file: file,
}
}
pub fn skip_if_no_chrome() -> bool {
if earl_protocol_browser::launcher::find_chrome().is_err() {
eprintln!("skipping — Chrome not found on this host");
return true;
}
false
}
pub fn make_context() -> ExecutionContext {
ExecutionContext {
key: "test".to_string(),
mode: CommandMode::Read,
allow_rules: vec![],
transport: ResolvedTransport {
timeout: Duration::from_secs(30),
follow_redirects: true,
max_redirect_hops: 10,
retry_max_attempts: 0,
retry_backoff: Duration::from_millis(100),
retry_on_status: vec![],
compression: false,
tls_min_version: None,
proxy_url: None,
max_response_bytes: 10_000_000,
},
result_template: ResultTemplate::default(),
args: Map::new(),
redactor: Redactor::new(vec![]),
}
}
pub async fn execute(data: PreparedBrowserCommand) -> anyhow::Result<Value> {
let mut executor = BrowserExecutor;
let result = executor.execute(&data, &make_context()).await?;
Ok(serde_json::from_slice(&result.body)?)
}