From c04551261d28aa73ac1d19a342f705241854b212 Mon Sep 17 00:00:00 2001 From: Franz Dietrich Date: Wed, 11 Sep 2024 15:16:12 +0200 Subject: [PATCH] Fix testing --- app/src/lib.rs | 15 +-- pslink/Cargo.toml | 13 +- pslink/tests/integration-tests.rs | 213 ++++++++++++++++++------------ 3 files changed, 133 insertions(+), 108 deletions(-) diff --git a/app/src/lib.rs b/app/src/lib.rs index a946fd8..f19e39b 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -297,12 +297,6 @@ pub struct Urls<'a> { impl<'a> Urls<'a> { /// Create a new `Urls` instance. - /// - /// # Example - /// - /// ```rust,no_run - /// Urls::new(base_url).home() - /// ``` pub fn new(base_url: impl Into>) -> Self { Self { base_url: base_url.into(), @@ -310,14 +304,7 @@ impl<'a> Urls<'a> { } /// Return base `Url`. If `base_url` isn't owned, it will be cloned. - /// - /// # Example - /// - /// ```rust,no_run - /// pub fn admin_urls(self) -> page::admin::Urls<'a> { - /// page::admin::Urls::new(self.base_url().add_path_part(ADMIN)) - /// } - /// ``` + #[must_use] pub fn base_url(self) -> Url { self.base_url.into_owned() diff --git a/pslink/Cargo.toml b/pslink/Cargo.toml index 0feef99..3636535 100644 --- a/pslink/Cargo.toml +++ b/pslink/Cargo.toml @@ -39,11 +39,11 @@ clap = { version = "4", features = [ dotenv = "0.15.0" fluent-langneg = "0.14" image = "0.25" -opentelemetry = { version = "0.24" } -opentelemetry_sdk = { version = "0.24", features = ["rt-tokio-current-thread"] } +opentelemetry = { version = "0.25" } +opentelemetry_sdk = { version = "0.25", features = ["rt-tokio-current-thread"] } opentelemetry-jaeger = "0.22" -opentelemetry-otlp = "0.17" -opentelemetry-semantic-conventions = "0.16" +opentelemetry-otlp = "0.25" +opentelemetry-semantic-conventions = "0.25" qrcode = "0.14" rand = "0.8" rpassword = "7.3" @@ -51,10 +51,10 @@ serde = "1.0" thiserror = "1.0" tracing-actix-web = "0.7" tracing-bunyan-formatter = "0.3.0" -tracing-opentelemetry = "0.25" +tracing-opentelemetry = "0.26" async-trait = "0.1" enum-map = { version = "2", features = ["serde"] } -reqwest = { version = "0.12.7", features = ["rustls-tls"] } +reqwest = { version = "0.12.7", features = ["rustls-tls", "json"] } reqwest_cookie_store = "0.8" shared = { path = "../shared" } @@ -82,6 +82,7 @@ actix-server = "2" tempdir = "0.3" test_bin = "0.4" tokio = "1" +serde_json = "1.0" [dev-dependencies.reqwest] features = ["cookies"] diff --git a/pslink/tests/integration-tests.rs b/pslink/tests/integration-tests.rs index bca938d..5b21c4c 100644 --- a/pslink/tests/integration-tests.rs +++ b/pslink/tests/integration-tests.rs @@ -1,20 +1,20 @@ -use shared::datatypes::Secret; +use serde_json::json; #[test] fn test_help_of_command_for_breaking_changes() { let output = test_bin::get_test_bin("pslink") .output() .expect("Failed to start pslink"); - assert!(String::from_utf8_lossy(&output.stdout).contains("USAGE")); + assert!(String::from_utf8_lossy(&output.stdout).contains("Usage")); let output = test_bin::get_test_bin("pslink") - .args(&["--help"]) + .args(["--help"]) .output() .expect("Failed to start pslink"); let outstring = String::from_utf8_lossy(&output.stdout); let args = &[ - "USAGE", + "Usage", "-h", "--help", "-b", @@ -44,7 +44,7 @@ fn test_generate_env() { use std::io::BufRead; let tmp_dir = tempdir::TempDir::new("pslink_test_env").expect("create temp dir"); let output = test_bin::get_test_bin("pslink") - .args(&["generate-env", "--secret", "abcdefghijklmnopqrstuvw"]) + .args(["generate-env", "--secret", "abcdefghijklmnopqrstuvw"]) .current_dir(&tmp_dir) .output() .expect("Failed to start pslink"); @@ -85,7 +85,7 @@ fn test_generate_env() { "The secret has not made it into the .env file!" ); let output = test_bin::get_test_bin("pslink") - .args(&["generate-env"]) + .args(["generate-env"]) .current_dir(&tmp_dir) .output() .expect("Failed to start pslink"); @@ -98,24 +98,26 @@ async fn test_migrate_database() { use std::io::Write; #[derive(serde::Serialize, Debug)] pub struct Count { - pub number: i32, + pub number: i64, } - + println!("Starting test_migrate_database"); let tmp_dir = tempdir::TempDir::new("pslink_test_env").expect("create temp dir"); + println!("Created temp dir"); // generate .env file let _output = test_bin::get_test_bin("pslink") - .args(&["generate-env"]) + .args(["generate-env"]) .current_dir(&tmp_dir) .output() .expect("Failed generate .env"); + println!("Generated .env file"); // migrate the database let output = test_bin::get_test_bin("pslink") - .args(&["migrate-database"]) + .args(["migrate-database"]) .current_dir(&tmp_dir) .output() .expect("Failed to migrate the database"); - println!("{}", String::from_utf8_lossy(&output.stdout)); + println!("Output: {}", String::from_utf8_lossy(&output.stdout)); // check if the users table exists by counting the number of admins. let db_pool = sqlx::pool::Pool::::connect( @@ -123,16 +125,19 @@ async fn test_migrate_database() { ) .await .expect("Error: Failed to connect to database!"); + println!("Connected to database"); let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2") .fetch_one(&db_pool) .await .unwrap(); + println!("Number of admins: {}", num.number); // initially no admin is present assert_eq!(num.number, 0, "Failed to create the database!"); + println!("Creating an admin"); // create a new admin let mut input = test_bin::get_test_bin("pslink") - .args(&["create-admin"]) + .args(["create-admin"]) .current_dir(&tmp_dir) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()) @@ -140,14 +145,32 @@ async fn test_migrate_database() { .expect("Failed to migrate the database"); let mut procin = input.stdin.take().unwrap(); - procin.write_all(b"test\n").unwrap(); - procin.write_all(b"test@mail.test\n").unwrap(); - procin.write_all(b"testpw\n").unwrap(); + async { + println!("Writing username"); + println!("Bytes written: {}", procin.write(b"test\n").unwrap()); + procin.flush().unwrap(); + } + .await; + async { + println!("Writing email"); + procin.write_all(b"test@mail.test\n").unwrap(); + procin.flush().unwrap(); + } + .await; + async { + println!("Writing password"); + procin.write_all(b"testpw\n").unwrap(); + procin.flush().unwrap(); + drop(procin); + } + .await; + //read_output(&mut procout); + println!("Waiting for process to finish"); let r = input.wait().unwrap(); - println!("Exitstatus is: {}", r); + println!("Exitstatus is: {:?}", r); + tokio::time::sleep(std::time::Duration::from_millis(100)).await; - println!("{}", String::from_utf8_lossy(&output.stdout)); let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2") .fetch_one(&db_pool) .await @@ -156,22 +179,25 @@ async fn test_migrate_database() { assert_eq!(num.number, 1, "Failed to create an admin!"); } -async fn run_server() { +async fn run_server() -> ( + tokio::task::JoinHandle>, + tempdir::TempDir, +) { use std::io::Write; #[derive(serde::Serialize, Debug)] pub struct Count { - pub number: i32, + pub number: i64, } let tmp_dir = tempdir::TempDir::new("pslink_test_env").expect("create temp dir"); // generate .env file let _output = test_bin::get_test_bin("pslink") - .args(&["generate-env", "--secret", "abcdefghijklmnopqrstuvw"]) + .args(["generate-env", "--secret", "abcdefghijklmnopqrstuvw"]) .current_dir(&tmp_dir) .output() .expect("Failed generate .env"); // migrate the database let output = test_bin::get_test_bin("pslink") - .args(&["migrate-database"]) + .args(["migrate-database"]) .current_dir(&tmp_dir) .output() .expect("Failed to migrate the database"); @@ -210,12 +236,12 @@ async fn run_server() { ); let server_config = pslink::ServerConfig { - secret: Secret::new("abcdefghijklmnopqrstuvw".to_string()), + secret: shared::datatypes::Secret::new("abcdefghijklmnopqrstuvw".to_string()), db: std::path::PathBuf::from("links.db"), db_pool, - public_url: "localhost:8080".to_string(), + public_url: "localhost:8085".to_string(), internal_ip: "localhost".to_string(), - port: 8080, + port: 8085, protocol: pslink::Protocol::Http, empty_forward_url: "https://github.com/enaut/pslink".to_string(), brand_name: "Pslink".to_string(), @@ -223,24 +249,40 @@ async fn run_server() { let server = pslink::webservice(server_config); - let _neveruse = tokio::spawn(server); + let server_handle = tokio::spawn( + server + .await + .map_err(|e| { + println!("{:?}", e); + std::thread::sleep(std::time::Duration::from_millis(100)); + std::process::exit(0); + }) + .expect("Failed to launch the service"), + ); + println!("Server started"); + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + println!("Waited for startup"); + (server_handle, tmp_dir) } #[actix_rt::test] async fn test_web_paths() { - run_server().await; - + let (server_handle, _tmp_dir) = run_server().await; + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + let cookie_store = reqwest_cookie_store::CookieStore::new(None); + let cookie_store = reqwest_cookie_store::CookieStoreMutex::new(cookie_store); + let cookie_store = std::sync::Arc::new(cookie_store); // We need to bring in `reqwest` // to perform HTTP requests against our application. let client = reqwest::Client::builder() - .cookie_store(true) + .cookie_provider(std::sync::Arc::clone(&cookie_store)) .redirect(reqwest::redirect::Policy::none()) .build() .unwrap(); // Act let response = client - .get("http://localhost:8080/") + .get("http://localhost:8085/") .send() .await .expect("Failed to execute request."); @@ -251,92 +293,85 @@ async fn test_web_paths() { assert!(location.to_str().unwrap().contains("github")); // Act + let json_data = json!({ + "username": "test", + "password": "testpw" + }); let response = client - .get("http://localhost:8080/admin/login/") - .send() - .await - .expect("Failed to execute request."); - - // The Loginpage is reachable and contains a password field! - assert!(response.status().is_success()); - let content = response.text().await.unwrap(); - assert!( - content.contains(r#""#), - "No Logout Button was found on /admin/index/!" + content.contains(r#"[]"#), + "The list of links is not empty: {}", + content ); // Act title=haupt&target=http%3A%2F%2Fdas.geht%2Fjetzt%2F&code=tpuah - let formdata = &[ - ("title", "haupt"), - ("target", "https://das.geht/jetzt/"), - ("code", "tpuah"), - ]; + use serde_json::json; + + let json_data = json!({ + "edit": "Create", + "id": null, + "title": "mytite", + "target": "https://github.com/enaut/pslink/", + "code": "mycode", + "author": 0, + "created_at": null + }); let response = client - .post("http://localhost:8080/admin/submit/") - .form(formdata) + .post("http://localhost:8085/admin/json/create_link/") + .json(&json_data) .send() .await .expect("Failed to execute request."); // It is possible to login - assert!(response.status().is_redirection()); - let location = response.headers().get("location").unwrap(); - assert_eq!("/admin/view/link/tpuah", location.to_str().unwrap()); + assert!(response.status().is_success()); + let response_text = response.text().await.unwrap(); + println!("Response of /admin/json/create_link/: {:?}", response_text); + assert!(response_text.contains("\"message\":\"Successfully saved link: mycode\"")); // Act let response = client - .get("http://localhost:8080/tpuah") + .get("http://localhost:8085/mycode") .send() .await .expect("Failed to execute request."); @@ -347,5 +382,7 @@ async fn test_web_paths() { assert!(location .to_str() .unwrap() - .contains("https://das.geht/jetzt/")); + .contains("https://github.com/enaut/pslink/")); + + server_handle.abort(); }