use crate::test_util::build_reference_test_runner::GlobalReplacement; use crate::test_util::constants::ABI_CLI; use crate::test_util::jar_util::{ assert_config_toml, create_abi_cmd, create_abi_cmd_with_url, default_abi_client_name, }; use crate::test_util::resource_test_util::assert_jar_files; use crate::test_util::{path_to_file_url, resource_folder_path}; use assert_cmd::prelude::OutputAssertExt; use assert_fs::TempDir; use base64::engine::general_purpose::STANDARD; use base64::Engine; use mockito::Matcher::Missing; use mockito::ServerGuard; use predicates::str::contains; use std::path::PathBuf; use test_context::{test_context, TestContext}; mod test_util; struct HttpMockContext { server: ServerGuard, reference_file: PathBuf, tempdir: TempDir, } impl TestContext for HttpMockContext { fn setup() -> Self { let tempdir = TempDir::new().unwrap(); let mut abi_cmd = create_abi_cmd(&tempdir.join("original_abi-cli")); abi_cmd.assert().success(); let server = mockito::Server::new(); let abi_client_file = tempdir .join("original_abi-cli") .join(default_abi_client_name()); HttpMockContext { server, reference_file: abi_client_file, tempdir, } } fn teardown(self) {} } #[test] fn test_fetch_abi_use_existing() { let tempdir = TempDir::new().unwrap(); let mut abi_cmd = create_abi_cmd(&tempdir); abi_cmd.assert(); let downloaded_file = tempdir.join(default_abi_client_name()); let globals: Vec = vec![]; assert_jar_files(&downloaded_file, &downloaded_file, &globals); // Do second call abi_cmd.assert().success().stdout(contains(format!( "Using existing {}", default_abi_client_name() ))); } #[test_context(HttpMockContext)] #[test] fn test_fail_404_fetch_abi(ctx: &mut HttpMockContext) { let HttpMockContext { server, tempdir, .. } = ctx; let mock = server.mock("GET", "/fail.jar").with_status(404).create(); let url = server.url() + "/fail.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); abi_cmd .assert() .failure() .stdout(contains("Fetching abi-cli: fail.jar, using Http")) .stdout(contains(format!("Failed to get {url} using http"))); mock.assert(); let config_path = tempdir.join("config.toml"); assert!(!config_path.exists()); } #[test_context(HttpMockContext)] #[test] fn test_fail_no_jar_fetch_abi(ctx: &mut HttpMockContext) { let HttpMockContext { server, tempdir, .. } = ctx; let mock = server .mock("GET", "/fail.jar") .with_header("content-type", "application/octet-stream") .with_status(200) .create(); let url = server.url() + "/fail.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); abi_cmd .assert() .failure() .stdout(contains("Fetching abi-cli: fail.jar, using Http")) .stdout(contains( "Jar command failed, see console output for more details.", )) .stderr(contains("Invalid or corrupt jarfile")); mock.assert(); // Even if the command failed we still want to save the jar let config_path = tempdir.join("config.toml"); assert!(config_path.exists()); } #[test_context(HttpMockContext)] #[test] fn test_abi_netrc_variable(ctx: &mut HttpMockContext) { let HttpMockContext { tempdir, reference_file, server, .. } = ctx; let base64_password_username = STANDARD.encode("my_awesome_username:my_awesome_password"); let expected_authorisation = format!("Basic {base64_password_username}"); let authenticated_mock = server .mock("GET", "/test.jar") .with_status(200) .with_body_from_file(reference_file) .with_header("content-type", "application/octet-stream") .match_header("authorization", expected_authorisation.as_str()) .create(); let url = server.url() + "/test.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); let resource_netrc = resource_folder_path() .join("test_abi_netrc_variable") .join("_netrc"); abi_cmd.env("NETRC", resource_netrc); abi_cmd .assert() .success() .stdout(contains("Fetching abi-cli: test.jar, using Http")); authenticated_mock.assert(); let downloaded_file = tempdir.join("test.jar"); let globals: Vec = vec![]; assert_jar_files(&downloaded_file, &downloaded_file, &globals); assert_config_toml(tempdir, ABI_CLI, &path_to_file_url(downloaded_file)); } #[test_context(HttpMockContext)] #[test] fn test_abi_netrc_default_variable(ctx: &mut HttpMockContext) { let HttpMockContext { tempdir, reference_file, server, .. } = ctx; let base64_password_username = STANDARD.encode("my_default_username:my_default_password"); let expected_authorisation = format!("Basic {base64_password_username}"); let authenticated_mock = server .mock("GET", "/test.jar") .with_status(200) .with_body_from_file(reference_file) .with_header("content-type", "application/octet-stream") .match_header("authorization", expected_authorisation.as_str()) .create(); let url = server.url() + "/test.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); let resource_netrc = resource_folder_path() .join("test_abi_netrc_default_variable") .join("_netrc"); abi_cmd.env("NETRC", resource_netrc); abi_cmd .assert() .success() .stdout(contains("Fetching abi-cli: test.jar, using Http")); authenticated_mock.assert(); let downloaded_file = tempdir.join("test.jar"); let globals: Vec = vec![]; assert_jar_files(&downloaded_file, &downloaded_file, &globals); assert_config_toml(tempdir, ABI_CLI, &path_to_file_url(downloaded_file)); } #[test_context(HttpMockContext)] #[test] fn test_abi_failed_authentication_missing_machine(ctx: &mut HttpMockContext) { let HttpMockContext { tempdir, server, .. } = ctx; let authenticated_mock = server.mock("GET", "/test.jar").with_status(401).create(); let url = server.url() + "/test.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); let resource_netrc = tempdir.join("_netrc"); abi_cmd.env("NETRC", resource_netrc); let host_with_port = server.host_with_port(); let host = host_with_port.split(':').next().unwrap(); abi_cmd .assert() .failure() .stdout(contains("Fetching abi-cli: test.jar, using Http")) .stdout(contains(format!( "Failed to get {url} using http - Error 401 Unauthorized" ))) .stdout(contains(format!( "netrc file is missing authentication for {host}" ))); authenticated_mock.assert(); } #[test_context(HttpMockContext)] #[test] fn test_abi_netrc_invalid_file(ctx: &mut HttpMockContext) { let HttpMockContext { tempdir, server, reference_file, .. } = ctx; let no_authorization_mock = server .mock("GET", "/test.jar") .with_status(200) .with_body_from_file(reference_file) .with_header("content-type", "application/octet-stream") .match_header("authorization", Missing) .create(); let url = server.url() + "/test.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); let resource_netrc = resource_folder_path() .join("test_abi_netrc_invalid_file") .join("_netrc"); abi_cmd.env("NETRC", resource_netrc); abi_cmd .assert() .success() .stdout(contains("Failed to parse netrc file")); no_authorization_mock.assert(); let downloaded_file = tempdir.join("test.jar"); let globals: Vec = vec![]; assert_jar_files(&downloaded_file, &downloaded_file, &globals); } #[test] fn test_abi_netrc_invalid_url() { let url = "http://[:::1]"; let tempdir = TempDir::new().unwrap(); let mut abi_cmd = create_abi_cmd_with_url(url, &tempdir); let resource_netrc = resource_folder_path() .join("test_abi_netrc_invalid_url") .join("_netrc"); abi_cmd.env("NETRC", resource_netrc); abi_cmd .assert() .failure() .stdout(contains("Failed to get file from: http://[:::1]")) .stdout(contains("Failed to parse url while getting netrc machine")) .stdout(contains("invalid IPv6 address")); } #[test_context(HttpMockContext)] #[test] fn test_abi_netrc_non_existent(ctx: &mut HttpMockContext) { let HttpMockContext { tempdir, reference_file, server, .. } = ctx; let authenticated_mock = server .mock("GET", "/test.jar") .with_status(200) .with_body_from_file(reference_file) .with_header("content-type", "application/octet-stream") .match_header("authorization", Missing) .create(); let url = server.url() + "/test.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); let resource_netrc = tempdir.join("non_existing"); abi_cmd.env("NETRC", resource_netrc); abi_cmd .assert() .success() .stdout(contains("Fetching abi-cli: test.jar, using Http")); authenticated_mock.assert(); let downloaded_file = tempdir.join("test.jar"); let globals: Vec = vec![]; assert_jar_files(&downloaded_file, &downloaded_file, &globals); assert_config_toml(tempdir, ABI_CLI, &path_to_file_url(downloaded_file)); } #[test_context(HttpMockContext)] #[test] fn test_abi_not_a_jar(ctx: &mut HttpMockContext) { let HttpMockContext { tempdir, server, .. } = ctx; let not_a_jar = resource_folder_path() .join("test_abi_not_a_jar") .join("not_a_jar.txt"); let mock = server .mock("GET", "/test.jar") .with_status(200) .with_body_from_file(not_a_jar) .with_header("content-type", "application/octet-stream") .create(); let url = server.url() + "/test.jar"; let mut abi_cmd = create_abi_cmd_with_url(&url, tempdir); abi_cmd .assert() .failure() .stdout(contains("Fetching abi-cli: test.jar, using Http")) .stdout(contains( "Jar command failed, see console output for more details.", )) .stderr(contains("Invalid or corrupt jarfile")); mock.assert(); }