// The MIT License (MIT) // // Copyright (c) 2024 Aliaksei Bialiauski // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #[allow(clippy::question_mark_used)] #[cfg(test)] mod tests { use anyhow::Result; use assert_cmd::Command; #[cfg_attr(target_os = "windows", allow(unused_imports))] use defer::defer; use std::str; #[cfg_attr(target_os = "windows", allow(unused_imports))] use std::time::Duration; use tagrs::tag; #[tag("deep")] #[test] fn outputs_help() -> Result<()> { let assertion = Command::cargo_bin("fakehub")?.arg("--help").assert(); let bytes = assertion.get_output().stdout.as_slice(); let output = str::from_utf8(bytes)?; assert!(output.contains("help")); assert!(output.contains("start")); assert!(output.contains("Start the server")); assert!(output.contains("--help")); assert!(output.contains("Print help")); Ok(()) } #[tag("deep")] #[test] fn outputs_version() -> Result<()> { let assertion = Command::cargo_bin("fakehub")?.arg("--version").assert(); let bytes = assertion.get_output().stdout.as_slice(); let output = str::from_utf8(bytes)?; assert!(output.contains(env!("CARGO_PKG_VERSION"))); Ok(()) } #[test] fn outputs_version_from_short() -> Result<()> { let assertion = Command::cargo_bin("fakehub")?.arg("-v").assert(); let bytes = assertion.get_output().stdout.as_slice(); let output = str::from_utf8(bytes)?; assert!(output.contains(env!("CARGO_PKG_VERSION"))); Ok(()) } #[tag("deep")] #[test] fn outputs_start_opts() -> Result<()> { let assertion = Command::cargo_bin("fakehub")? .arg("start") .arg("--help") .assert(); let bytes = assertion.get_output().stdout.as_slice(); let output = str::from_utf8(bytes)?; assert!(output.contains("-p")); assert!(output.contains("--port")); assert!(output.contains("The port to run [default: 3000]")); assert!(output.contains("-v")); assert!(output.contains("--verbose")); assert!(output.contains("Verbose output")); assert!(output.contains("-d")); assert!(output.contains("--detach")); assert!(output.contains("Run in detach mode")); Ok(()) } // @todo #129:35min Find a way to run slow tests separately from fast tests. // This test `accepts_request_in_detached_mode` runs a way longer than // other unit tests. Let's mark such long tests as slow and run them // separately from fast test. Locally, developers will run only fast // tests, while CI server will run both. Check // this link // for more information about this idea. #[tokio::test] #[cfg(not(target_os = "windows"))] // @todo #129:60min Create similar integration test for windows platform. // Now we have test for linux and macos. However, we need to maintain // similar test case for windows as well. async fn accepts_request_in_detached_mode() -> Result<()> { let _defer = defer(|| kill(3000)); let assertion = Command::cargo_bin("fakehub")? .arg("start") .arg("-d") .assert(); let bytes = assertion.get_output().stdout.as_slice(); let output = str::from_utf8(bytes)?; assert!( output.contains("Server is running in detached mode on port 3000"), "Output should contain logs that server started in detached mode" ); let request = reqwest::Client::new(); let mut retries = 10; let mut status = None; while retries > 0 { tokio::time::sleep(Duration::from_secs(1)).await; match request.get("http://localhost:3000").send().await { Ok(home) => { status = Some(home.status()); break; } Err(_) => { retries -= 1; } } } assert_eq!(status.expect("Failed to retrieve status"), 200); Ok(()) } #[cfg_attr(target_os = "windows", allow(dead_code))] fn kill(port: usize) { std::process::Command::new("sh") .arg("-c") .arg(format!("killport {}", port)) .output() .unwrap_or_else(|_| panic!("Failed to kill process on port {}", port)); } // @todo #43:30min Enable starts_server integration test. // We should enable this integration test that checks whether server starts or // not. This test should output success message in info!. For now it does not // work. Probably some error with logging configuration. Don't forget to // remove this puzzle. #[test] #[ignore] fn starts_server() -> Result<()> { let assertion = Command::cargo_bin("fakehub")? .arg("start") .arg("--port 8080") .assert(); let bytes = assertion.get_output().stdout.as_slice(); let output = str::from_utf8(bytes)?; assert!(output.contains("Server started successfully on port 8080")); Ok(()) } // @todo #82:30min Enable runs_in_verbose_mode test. // We should enable this test right after we find out how to shutdown the server // in test. This problem is similar to // https://github.com/h1alexbel/fakehub/issues/76. #[test] #[ignore] fn runs_in_verbose_mode() -> Result<()> { let assertion = Command::cargo_bin("fakehub")? .arg("start") .arg("--verbose") .assert(); let bytes = assertion.get_output().stdout.as_slice(); let output = str::from_utf8(bytes)?; assert!(output.contains("DEBUG")); Ok(()) } }