From 488c942400084d5fa9320413800405c3277e5d26 Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Wed, 22 May 2024 13:10:33 +0200 Subject: [PATCH 1/3] feat(cli): Deploy and create integration tests Add integration tests for the *deploy* command - Deploy a PHP app, check w/ random query param - Deploy a JS app, check w/ random query param - Deploy an Axum server, check w/ random query param - Deploy a static website, check w/ random contents ..and *create* command - Create a new app from an existing package (wasmer/hello) - Create a new app from a template (static-website) --- tests/integration/cli/tests/create.rs | 145 ++++++++++++++ tests/integration/cli/tests/deploy.rs | 169 +++++++++++++--- .../cli/tests/packages/axum/Cargo.toml | 20 ++ .../cli/tests/packages/axum/app.yaml | 2 + .../cli/tests/packages/axum/src/main.rs | 25 +++ .../cli/tests/packages/axum/wasmer.toml | 8 + .../cli/tests/packages/js/README.md | 26 +++ .../cli/tests/packages/js/app.yaml | 2 + .../cli/tests/packages/js/src/index.js | 187 ++++++++++++++++++ .../cli/tests/packages/js/wasmer.toml | 14 ++ .../cli/tests/packages/php/wasmer.toml | 12 ++ .../tests/packages/static_website/wasmer.toml | 10 + 12 files changed, 598 insertions(+), 22 deletions(-) create mode 100644 tests/integration/cli/tests/create.rs create mode 100644 tests/integration/cli/tests/packages/axum/Cargo.toml create mode 100644 tests/integration/cli/tests/packages/axum/app.yaml create mode 100644 tests/integration/cli/tests/packages/axum/src/main.rs create mode 100644 tests/integration/cli/tests/packages/axum/wasmer.toml create mode 100644 tests/integration/cli/tests/packages/js/README.md create mode 100644 tests/integration/cli/tests/packages/js/app.yaml create mode 100644 tests/integration/cli/tests/packages/js/src/index.js create mode 100644 tests/integration/cli/tests/packages/js/wasmer.toml create mode 100644 tests/integration/cli/tests/packages/php/wasmer.toml create mode 100644 tests/integration/cli/tests/packages/static_website/wasmer.toml diff --git a/tests/integration/cli/tests/create.rs b/tests/integration/cli/tests/create.rs new file mode 100644 index 00000000000..3a929a628d4 --- /dev/null +++ b/tests/integration/cli/tests/create.rs @@ -0,0 +1,145 @@ +use assert_cmd::prelude::OutputAssertExt; +use std::{ + fs::OpenOptions, + path::{Path, PathBuf}, +}; +use wasmer_integration_tests_cli::get_wasmer_path; + +fn project_root() -> &'static Path { + Path::new(env!("CARGO_MANIFEST_DIR")) + .ancestors() + .nth(3) + .unwrap() +} + +fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { + std::fs::create_dir_all(&dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} + +#[test] +fn wasmer_create_package() -> anyhow::Result<()> { + // Only run this test in the CI + if std::env::var("GITHUB_TOKEN").is_err() { + return Ok(()); + } + + let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); + + let username = "ciuser"; + let app_name = format!("ci-create-replica-{}", rand::random::()); + + let tempdir = tempfile::tempdir()?; + let app_dir = tempdir.path(); + + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("app") + .arg("create") + .arg("--quiet") + .arg(format!("--name={app_name}")) + .arg(format!("--owner={username}")) + .arg(format!("--package=wasmer/hello")) + .arg(format!("--dir={}", app_dir.display())) + .arg(format!("--non-interactive")) + .arg("--registry=https://registry.wasmer.wtf/graphql"); + + if let Some(token) = wapm_dev_token { + // Special case: GitHub secrets aren't visible to outside collaborators + if token.is_empty() { + return Ok(()); + } + cmd.arg("--token").arg(token); + } + + cmd.assert().success(); + + let want = format!( + r#"kind: wasmer.io/App.v0 +name: {app_name} +owner: {username} +package: wasmer/hello +"# + ); + let got = std::fs::read_to_string(app_dir.join("app.yaml"))?; + assert_eq!(got, want); + + Ok(()) +} + +#[test] +fn wasmer_create_template() -> anyhow::Result<()> { + // Only run this test in the CI + if std::env::var("GITHUB_TOKEN").is_err() { + return Ok(()); + } + + let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); + + let username = "ciuser"; + let app_name = format!("ci-create-replica-{}", rand::random::()); + + let tempdir = tempfile::tempdir()?; + let app_dir = tempdir.path(); + + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("app") + .arg("create") + .arg("--quiet") + .arg(format!("--name={app_name}")) + .arg(format!("--owner={username}")) + .arg(format!("--template=static-website")) + .arg(format!("--dir={}", app_dir.display())) + .arg(format!("--non-interactive")) + .arg("--registry=https://registry.wasmer.wtf/graphql"); + + if let Some(token) = wapm_dev_token { + // Special case: GitHub secrets aren't visible to outside collaborators + if token.is_empty() { + return Ok(()); + } + cmd.arg("--token").arg(token); + } + + cmd.assert().success(); + + let want = format!( + r#"kind: wasmer.io/App.v0 +package: . +name: {app_name} +owner: {username} +"# + ); + let got = std::fs::read_to_string(app_dir.clone().join("app.yaml"))?; + assert_eq!(got, want); + + let want = format!( + r#"[dependencies] +"wasmer/static-web-server" = "^1" + +[fs] +"/public" = "public" +"/settings" = "settings" + +[[command]] +name = "script" +module = "wasmer/static-web-server:webserver" +runner = "https://webc.org/runner/wasi" + +[command.annotations.wasi] +main-args = ["-w", "/settings/config.toml"] +"# + ); + let got = std::fs::read_to_string(app_dir.join("wasmer.toml"))?; + assert_eq!(got, want); + + Ok(()) +} diff --git a/tests/integration/cli/tests/deploy.rs b/tests/integration/cli/tests/deploy.rs index ad98b4abbc9..98282459eaf 100644 --- a/tests/integration/cli/tests/deploy.rs +++ b/tests/integration/cli/tests/deploy.rs @@ -36,7 +36,7 @@ fn wasmer_deploy_php() -> anyhow::Result<()> { let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; - let app_name = format!("ci-php-replica-{}", rand::random::()); + let app_name = format!("ci-{}", rand::random::()); let random3 = format!("{}", rand::random::()); let php_app_dir = project_root() @@ -60,11 +60,12 @@ fn wasmer_deploy_php() -> anyhow::Result<()> { let mut cmd = std::process::Command::new(get_wasmer_path()); cmd.arg("deploy") - .arg("--quiet") + .arg("--non-interactive") + .arg("-vvvvvv") .arg(format!("--app-name={app_name}")) .arg(format!("--owner={username}")) - .arg(format!("--path={}", app_dir.display())) - .arg("--registry=https://registry.wasmer.wtf/graphql"); + .arg(format!("--dir={}", app_dir.display())) + .arg("--registry=wasmer.wtf"); if let Some(token) = wapm_dev_token { // Special case: GitHub secrets aren't visible to outside collaborators @@ -78,10 +79,7 @@ fn wasmer_deploy_php() -> anyhow::Result<()> { cmd.assert() .success() - .stderr(predicates::boolean::AndPredicate::new( - predicates::str::contains("Deployment complete"), - predicates::str::contains(&app_url), - )); + .stderr(predicates::str::contains("Deployment complete")); let r = reqwest::blocking::Client::new(); let r = r.get(app_url).query(&[("ci_rand", &random3)]).send()?; @@ -102,7 +100,7 @@ fn wasmer_deploy_static_website() -> anyhow::Result<()> { let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; - let app_name = format!("ci-static-website-replica-{}", rand::random::()); + let app_name = format!("ci-{}", rand::random::()); let random3 = format!("{}", rand::random::()); let src_app_dir = project_root() @@ -124,12 +122,6 @@ fn wasmer_deploy_static_website() -> anyhow::Result<()> { let app_dir = app_dir.join("static_website"); - let mut cmd = std::process::Command::new("sed"); - cmd.arg("-r") - .arg(format!("{}", src_app_dir.display())) - .arg(format!("{}", app_dir.display())) - .output()?; - let index_file_path = app_dir.join("public").join("index.html"); let contents = std::fs::read_to_string(&index_file_path)?; let new = contents.replace("RANDOM_NUMBER", &random3); @@ -144,11 +136,12 @@ fn wasmer_deploy_static_website() -> anyhow::Result<()> { let mut cmd = std::process::Command::new(get_wasmer_path()); cmd.arg("deploy") // .arg("--quiet") - .arg("-vvvvv") + .arg("--non-interactive") + .arg("-vvvvvv") .arg(format!("--app-name={app_name}")) .arg(format!("--owner={username}")) - .arg(format!("--path={}", app_dir.display())) - .arg("--registry=https://registry.wasmer.wtf/graphql"); + .arg(format!("--dir={}", app_dir.display())) + .arg("--registry=wasmer.wtf"); if let Some(token) = wapm_dev_token { // Special case: GitHub secrets aren't visible to outside collaborators @@ -162,10 +155,7 @@ fn wasmer_deploy_static_website() -> anyhow::Result<()> { cmd.assert() .success() - .stderr(predicates::boolean::AndPredicate::new( - predicates::str::contains("Deployment complete"), - predicates::str::contains(&app_url), - )); + .stderr(predicates::str::contains("Deployment complete")); let r = reqwest::blocking::Client::new(); let r = r.get(app_url).send()?; @@ -175,3 +165,138 @@ fn wasmer_deploy_static_website() -> anyhow::Result<()> { Ok(()) } + +#[test] +fn wasmer_deploy_js() -> anyhow::Result<()> { + // Only run this test in the CI + if std::env::var("GITHUB_TOKEN").is_err() { + return Ok(()); + } + + let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); + + let username = "ciuser"; + let app_name = format!("ci-{}", rand::random::()); + let random3 = format!("{}", rand::random::()); + + let src_app_dir = project_root() + .join("tests") + .join("integration") + .join("cli") + .join("tests") + .join("packages") + .join("js"); + + let tempdir = tempfile::tempdir()?; + let app_dir = tempdir.path(); + + let mut cmd = std::process::Command::new("cp"); + cmd.arg("-r") + .arg(format!("{}", src_app_dir.display())) + .arg(format!("{}", app_dir.display())) + .output()?; + + let app_dir = app_dir.join("js"); + + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("deploy") + // .arg("--quiet") + .arg("--non-interactive") + .arg("-vvvvvv") + .arg(format!("--app-name={app_name}")) + .arg(format!("--owner={username}")) + .arg(format!("--dir={}", app_dir.display())) + .arg("--registry=wasmer.wtf"); + + if let Some(token) = wapm_dev_token { + // Special case: GitHub secrets aren't visible to outside collaborators + if token.is_empty() { + return Ok(()); + } + cmd.arg("--token").arg(token); + } + + let app_url = format!("https://{app_name}-{username}.wasmer.dev"); + + cmd.assert() + .success() + .stderr(predicates::str::contains("Deployment complete")); + + let r = reqwest::blocking::Client::new(); + let r = r.get(app_url).query(&[("ci_rand", &random3)]).send()?; + let r = r.text()?; + + assert!(r.contains(&random3)); + + Ok(()) +} + +#[test] +fn wasmer_deploy_axum() -> anyhow::Result<()> { + // Only run this test in the CI + if std::env::var("GITHUB_TOKEN").is_err() { + return Ok(()); + } + + let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); + + let username = "ciuser"; + let app_name = format!("ci-{}", rand::random::()); + let random3 = format!("{}", rand::random::()); + + let src_app_dir = project_root() + .join("tests") + .join("integration") + .join("cli") + .join("tests") + .join("packages") + .join("axum"); + + let tempdir = tempfile::tempdir()?; + let app_dir = tempdir.path(); + + let mut cmd = std::process::Command::new("cp"); + cmd.arg("-r") + .arg(format!("{}", src_app_dir.display())) + .arg(format!("{}", app_dir.display())) + .output()?; + + let app_dir = app_dir.join("axum"); + + std::env::set_current_dir(&app_dir)?; + + let mut cmd = std::process::Command::new("cargo"); + cmd.arg("wasix").arg("build").output()?; + + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("deploy") + // .arg("--quiet") + .arg("--non-interactive") + .arg("-vvvvvv") + .arg(format!("--app-name={app_name}")) + .arg(format!("--owner={username}")) + .arg(format!("--dir={}", app_dir.display())) + .arg("--registry=wasmer.wtf"); + + if let Some(token) = wapm_dev_token { + // Special case: GitHub secrets aren't visible to outside collaborators + if token.is_empty() { + return Ok(()); + } + cmd.arg("--token").arg(token); + } + + let app_url = format!("https://{app_name}-{username}.wasmer.dev"); + + cmd.assert() + .success() + .stderr(predicates::str::contains("Deployment complete")); + + let r = reqwest::blocking::Client::new(); + let r = r.get(app_url).query(&[("ci_rand", &random3)]).send()?; + let r = r.text()?; + + assert!(r.contains(&random3)); + + Ok(()) +} diff --git a/tests/integration/cli/tests/packages/axum/Cargo.toml b/tests/integration/cli/tests/packages/axum/Cargo.toml new file mode 100644 index 00000000000..ee730b73da7 --- /dev/null +++ b/tests/integration/cli/tests/packages/axum/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "wasix-axum" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { version = "=0.6.9", features = ["tokio", "json"] } +serde = { version = "1.0.160", features = ["derive"] } +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.16", features = ["fmt"] } + +# NOTE: We need to pin and replace some dependencies to achieve wasix compatibility. +tokio = { version = "=1.24.2", default-features = false, features = ["full"] } +parking_lot = { version = "=0.12.1", features = ["nightly"] } + +[patch.crates-io] +tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "wasix-1.24.2" } +socket2 = { git = "https://github.com/wasix-org/socket2.git", branch = "v0.4.9" } +libc = { git = "https://github.com/wasix-org/libc.git", branch = "master" } +parking_lot = { git = "https://github.com/wasix-org/parking_lot", branch = "master" } diff --git a/tests/integration/cli/tests/packages/axum/app.yaml b/tests/integration/cli/tests/packages/axum/app.yaml new file mode 100644 index 00000000000..73a43009264 --- /dev/null +++ b/tests/integration/cli/tests/packages/axum/app.yaml @@ -0,0 +1,2 @@ +kind: wasmer.io/App.v0 +package: . diff --git a/tests/integration/cli/tests/packages/axum/src/main.rs b/tests/integration/cli/tests/packages/axum/src/main.rs new file mode 100644 index 00000000000..94658c2b385 --- /dev/null +++ b/tests/integration/cli/tests/packages/axum/src/main.rs @@ -0,0 +1,25 @@ +use axum::{extract::Query, routing::get, Router}; +use std::{collections::HashMap, net::SocketAddr}; + +#[tokio::main] +async fn main() { + // Building our application with a single Route + let app = Router::new().route("/", get(handler)); + + let port = std::env::var("PORT").unwrap_or("80".to_string()); + let port = port.parse::().unwrap_or_else(|_| { + eprintln!("Invalid port number: {}", port); + std::process::exit(1); + }); + // Run the server with hyper on http://127.0.0.1:3000 + let addr = SocketAddr::from(([127, 0, 0, 1], port)); + eprintln!("Listening on http://{}", addr); + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await + .unwrap(); +} + +async fn handler(Query(params): Query>) -> String { + format!("{:?}", params) +} diff --git a/tests/integration/cli/tests/packages/axum/wasmer.toml b/tests/integration/cli/tests/packages/axum/wasmer.toml new file mode 100644 index 00000000000..ce9022388f4 --- /dev/null +++ b/tests/integration/cli/tests/packages/axum/wasmer.toml @@ -0,0 +1,8 @@ +[[module]] +name = "wasix-axum" +source = "target/wasm32-wasmer-wasi/debug/wasix-axum.wasm" + +[[command]] +name = "wasix-axum" +module = "wasix-axum" +runner = "wasi@unstable_" diff --git a/tests/integration/cli/tests/packages/js/README.md b/tests/integration/cli/tests/packages/js/README.md new file mode 100644 index 00000000000..d1b40750df0 --- /dev/null +++ b/tests/integration/cli/tests/packages/js/README.md @@ -0,0 +1,26 @@ +This is a simple [Javascript Service Worker](https://python.org/) server template running with [WinterJS](https://github.com/wasmerio/winterjs). + +> This starter's full tutorial is available [here](https://docs.wasmer.io/edge/quickstart/js-wintercg). + +## Usage + +Modify the logic of your the Javascript worker in the `src/index.js` file. + +You can run the JS Service Worker locally with (check out the [Wasmer install guide](https://docs.wasmer.io/install)): + +```bash +wasmer run . --net +``` + +Open [http://localhost:8080](http://localhost:8080) with your browser to see the worker working! + + +## Deploy on Wasmer Edge + +The easiest way to deploy your Javascript Worker is to use the [Wasmer Edge](https://wasmer.io/products/edge). + +Live example: https://wasmer-js-worker-starter.wasmer.app/ + +```bash +wasmer deploy +``` diff --git a/tests/integration/cli/tests/packages/js/app.yaml b/tests/integration/cli/tests/packages/js/app.yaml new file mode 100644 index 00000000000..73a43009264 --- /dev/null +++ b/tests/integration/cli/tests/packages/js/app.yaml @@ -0,0 +1,2 @@ +kind: wasmer.io/App.v0 +package: . diff --git a/tests/integration/cli/tests/packages/js/src/index.js b/tests/integration/cli/tests/packages/js/src/index.js new file mode 100644 index 00000000000..2a7d61db7c0 --- /dev/null +++ b/tests/integration/cli/tests/packages/js/src/index.js @@ -0,0 +1,187 @@ +async function handleRequest(req) { + const accept = req.headers.get('accept') ?? ''; + const url = new URL(req.url); + const queryFormat = url.searchParams.get('format'); + + let outputFormat = 'html'; + + if (queryFormat) { + switch (queryFormat) { + case 'json': + outputFormat = 'json'; + break; + case 'html': + outputFormat = 'html'; + break; + case 'echo': + outputFormat = 'echo'; + break; + } + } else if (accept) { + if (accept.startsWith('application/json')) { + outputFormat = 'json'; + } else if (accept.search('text/html') !== -1) { + outputFormat = 'html'; + } + } + + switch (outputFormat) { + case 'json': + return buildResponseJson(req); + case 'html': + return buildResponseHtml(req); + case 'echo': + return buildResponseEcho(req); + } +} + +async function requestBodyToString(req) { + try { + const body = await req.text(); + return !body ? '' : body; + } catch (e) { + console.warn("Could not decode request body", e); + return ""; + } +} + + +addEventListener("fetch", (ev) => { + ev.respondWith(handleRequest(ev.request)); +}); + +async function buildResponseJson(req) { + const reqBody = await requestBodyToString(req); + + const data = { + url: req.url, + method: req.method, + headers: Object.fromEntries(req.headers), + body: reqBody, + }; + const body = JSON.stringify(data, null, 2); + return new Response(body, { + headers: { "content-type": "application/json" }, + }); +} + +async function buildResponseHtml(req) { + + let headers = ''; + + for (const [key, value] of req.headers.entries()) { + headers += ` + + ${key} + ${value} + `; + } + + const url = new URL(req.url); + url.searchParams.set('format', 'json'); + const jsonUrl = url.pathname + url.search; + + const reqBody = await requestBodyToString(req); + + let html = ` + + + + + + + + HTTP-Info - Analyze HTTP requests + + + +
+
+

+ HTTP-Info +

+ +
+ JSON +
+ + + + + + + + + + + + + + + + + + + + + + +
URL${req.url}
Method${req.method}
Headers + + + ${headers} + +
+
Body${reqBody}
+ +
+
+

Info

+
+
+

This service provides information about the incoming HTTP request. + It is useful for debugging and analyzing HTTP clients.

+ +

You can control the output format by:

+ +
    +
  • Setting the Accept header to application/json or text/html
  • +
  • + Setting the ?format=XXX query parameter to + json, html or echo
  • . +
+ +

+ By default the output format is html.
+ If the format is echo, the response will contain + the request headers and body unchanged. +

+ +
+
+ + +
+ +
+ + + `; + + return new Response(html, { + headers: { "content-type": "text/html" }, + }); +} + +function buildResponseEcho(req) { + return new Response(req.body, { + headers: req.headers, + }); +} diff --git a/tests/integration/cli/tests/packages/js/wasmer.toml b/tests/integration/cli/tests/packages/js/wasmer.toml new file mode 100644 index 00000000000..d2768384257 --- /dev/null +++ b/tests/integration/cli/tests/packages/js/wasmer.toml @@ -0,0 +1,14 @@ +[dependencies] +"wasmer/winterjs" = "*" + +[fs] +"/src" = "./src" + +[[command]] +name = "script" +module = "wasmer/winterjs:winterjs" +runner = "https://webc.org/runner/wasi" + +[command.annotations.wasi] +env = ["JS_PATH=/src/index.js"] +main-args = ["/src/index.js"] diff --git a/tests/integration/cli/tests/packages/php/wasmer.toml b/tests/integration/cli/tests/packages/php/wasmer.toml new file mode 100644 index 00000000000..f2be1cc9658 --- /dev/null +++ b/tests/integration/cli/tests/packages/php/wasmer.toml @@ -0,0 +1,12 @@ +[dependencies] +"php/php" = "=8.3.4-beta.1" + +[fs] +"/app" = "app" + +[[command]] +name = "run" +module = "php/php:php" +runner = "wasi" +[command.annotations.wasi] +main-args = ["-t", "/app", "-S", "localhost:8080"] diff --git a/tests/integration/cli/tests/packages/static_website/wasmer.toml b/tests/integration/cli/tests/packages/static_website/wasmer.toml new file mode 100644 index 00000000000..18bbd328958 --- /dev/null +++ b/tests/integration/cli/tests/packages/static_website/wasmer.toml @@ -0,0 +1,10 @@ +[dependencies] +"wasmer/static-web-server" = "^1" + +[fs] +"/public" = "public" + +[[command]] +name = "script" +module = "wasmer/static-web-server:webserver" +runner = "https://webc.org/runner/wasi" From c5ddcfb8fbb4fb945fd9f18e9230c9c38a6e3026 Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Wed, 22 May 2024 13:22:02 +0200 Subject: [PATCH 2/3] fix(cli/tests): Make linter happy --- tests/integration/cli/tests/create.rs | 27 +-------------------------- tests/integration/cli/tests/deploy.rs | 19 +------------------ 2 files changed, 2 insertions(+), 44 deletions(-) diff --git a/tests/integration/cli/tests/create.rs b/tests/integration/cli/tests/create.rs index 3a929a628d4..9c0d0877580 100644 --- a/tests/integration/cli/tests/create.rs +++ b/tests/integration/cli/tests/create.rs @@ -1,31 +1,6 @@ use assert_cmd::prelude::OutputAssertExt; -use std::{ - fs::OpenOptions, - path::{Path, PathBuf}, -}; use wasmer_integration_tests_cli::get_wasmer_path; -fn project_root() -> &'static Path { - Path::new(env!("CARGO_MANIFEST_DIR")) - .ancestors() - .nth(3) - .unwrap() -} - -fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - std::fs::create_dir_all(&dst)?; - for entry in std::fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; - } else { - std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; - } - } - Ok(()) -} - #[test] fn wasmer_create_package() -> anyhow::Result<()> { // Only run this test in the CI @@ -118,7 +93,7 @@ name: {app_name} owner: {username} "# ); - let got = std::fs::read_to_string(app_dir.clone().join("app.yaml"))?; + let got = std::fs::read_to_string(app_dir.join("app.yaml"))?; assert_eq!(got, want); let want = format!( diff --git a/tests/integration/cli/tests/deploy.rs b/tests/integration/cli/tests/deploy.rs index 98282459eaf..ec224eed97c 100644 --- a/tests/integration/cli/tests/deploy.rs +++ b/tests/integration/cli/tests/deploy.rs @@ -1,8 +1,5 @@ use assert_cmd::prelude::OutputAssertExt; -use std::{ - fs::OpenOptions, - path::{Path, PathBuf}, -}; +use std::{fs::OpenOptions, path::Path}; use wasmer_integration_tests_cli::get_wasmer_path; fn project_root() -> &'static Path { @@ -12,20 +9,6 @@ fn project_root() -> &'static Path { .unwrap() } -fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - std::fs::create_dir_all(&dst)?; - for entry in std::fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; - } else { - std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; - } - } - Ok(()) -} - #[test] fn wasmer_deploy_php() -> anyhow::Result<()> { // Only run this test in the CI From cd16429d7f69826158d415f9298b6a9196eb9f09 Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Wed, 22 May 2024 18:39:47 +0200 Subject: [PATCH 3/3] feat(cli/CI): run CI tests locally as well --- tests/integration/cli/tests/create.rs | 10 --- tests/integration/cli/tests/deploy.rs | 96 ++++++++++++++++++++------ tests/integration/cli/tests/publish.rs | 84 +++++++++++++++------- 3 files changed, 135 insertions(+), 55 deletions(-) diff --git a/tests/integration/cli/tests/create.rs b/tests/integration/cli/tests/create.rs index 9c0d0877580..9b553c430d1 100644 --- a/tests/integration/cli/tests/create.rs +++ b/tests/integration/cli/tests/create.rs @@ -3,11 +3,6 @@ use wasmer_integration_tests_cli::get_wasmer_path; #[test] fn wasmer_create_package() -> anyhow::Result<()> { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); - } - let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; @@ -52,11 +47,6 @@ package: wasmer/hello #[test] fn wasmer_create_template() -> anyhow::Result<()> { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); - } - let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; diff --git a/tests/integration/cli/tests/deploy.rs b/tests/integration/cli/tests/deploy.rs index ec224eed97c..4b269ea8dae 100644 --- a/tests/integration/cli/tests/deploy.rs +++ b/tests/integration/cli/tests/deploy.rs @@ -11,11 +11,6 @@ fn project_root() -> &'static Path { #[test] fn wasmer_deploy_php() -> anyhow::Result<()> { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); - } - let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; @@ -75,11 +70,6 @@ fn wasmer_deploy_php() -> anyhow::Result<()> { #[test] fn wasmer_deploy_static_website() -> anyhow::Result<()> { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); - } - let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; @@ -151,11 +141,6 @@ fn wasmer_deploy_static_website() -> anyhow::Result<()> { #[test] fn wasmer_deploy_js() -> anyhow::Result<()> { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); - } - let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; @@ -215,12 +200,83 @@ fn wasmer_deploy_js() -> anyhow::Result<()> { } #[test] -fn wasmer_deploy_axum() -> anyhow::Result<()> { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return Ok(()); - } +fn wasmer_deploy_fails_no_app_name() -> anyhow::Result<()> { + let username = "ciuser"; + + let php_app_dir = project_root() + .join("tests") + .join("integration") + .join("cli") + .join("tests") + .join("packages") + .join("php"); + + let tempdir = tempfile::tempdir()?; + let app_dir = tempdir.path(); + let mut cmd = std::process::Command::new("cp"); + cmd.arg("-r") + .arg(format!("{}", php_app_dir.display())) + .arg(format!("{}", app_dir.display())) + .output()?; + + let app_dir = app_dir.join("php"); + + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("deploy") + .arg("--non-interactive") + .arg("-vvvvvv") + .arg(format!("--owner={username}")) + .arg(format!("--dir={}", app_dir.display())) + .arg("--registry=wasmer.wtf"); + + cmd.assert().failure().stderr(predicates::str::contains( + "The app.yaml does not specify any app name.", + )); + + Ok(()) +} + +#[test] +fn wasmer_deploy_fails_no_owner() -> anyhow::Result<()> { + let app_name = format!("ci-{}", rand::random::()); + + let php_app_dir = project_root() + .join("tests") + .join("integration") + .join("cli") + .join("tests") + .join("packages") + .join("php"); + + let tempdir = tempfile::tempdir()?; + let app_dir = tempdir.path(); + + let mut cmd = std::process::Command::new("cp"); + cmd.arg("-r") + .arg(format!("{}", php_app_dir.display())) + .arg(format!("{}", app_dir.display())) + .output()?; + + let app_dir = app_dir.join("php"); + + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("deploy") + .arg("--non-interactive") + .arg("-vvvvvv") + .arg(format!("--app-name={app_name}")) + .arg(format!("--dir={}", app_dir.display())) + .arg("--registry=wasmer.wtf"); + + cmd.assert() + .failure() + .stderr(predicates::str::contains("No owner specified")); + + Ok(()) +} + +#[test] +fn wasmer_deploy_axum() -> anyhow::Result<()> { let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let username = "ciuser"; diff --git a/tests/integration/cli/tests/publish.rs b/tests/integration/cli/tests/publish.rs index 003cd6ff743..c58a224a238 100644 --- a/tests/integration/cli/tests/publish.rs +++ b/tests/integration/cli/tests/publish.rs @@ -3,12 +3,54 @@ use predicates::str::contains; use wasmer_integration_tests_cli::{fixtures, get_wasmer_path}; #[test] -fn wasmer_publish() { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return; +fn wasmer_publish_bump() { + let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path(); + let username = "ciuser"; + + let random1 = format!("{}", rand::random::()); + let random2 = format!("{}", rand::random::()); + let random3 = format!("{}", rand::random::()); + + std::fs::copy(fixtures::qjs(), path.join("largewasmfile.wasm")).unwrap(); + std::fs::write( + path.join("wasmer.toml"), + include_str!("./fixtures/init6.toml") + .replace("WAPMUSERNAME", username) // <-- TODO! + .replace("RANDOMVERSION1", &random1) + .replace("RANDOMVERSION2", &random2) + .replace("RANDOMVERSION3", &random3), + ) + .unwrap(); + + let mut cmd = std::process::Command::new(get_wasmer_path()); + cmd.arg("publish") + .arg("--quiet") + .arg("--bump") + .arg("--registry=wasmer.wtf") + .arg(path); + + if let Some(token) = wapm_dev_token { + // Special case: GitHub secrets aren't visible to outside collaborators + if token.is_empty() { + return; + } + cmd.arg("--token").arg(token); } + // What comes to mind is that we should check that the actual published version is + // random1.random2.(random3 + 1), but if a higher version is already in the registry bumping + // will actually bump the *other* version.. + cmd.assert() + .success() + .stderr(predicates::str::contains(format!( + "wasmer.wtf/{username}/largewasmfile" + ))); +} + +#[test] +fn wasmer_publish() { let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let tempdir = tempfile::tempdir().unwrap(); let path = tempdir.path(); @@ -43,20 +85,17 @@ fn wasmer_publish() { cmd.arg("--token").arg(token); } - cmd.assert().success().stdout(format!( - "🚀 Successfully published package `{username}/largewasmfile@{random1}.{random2}.{random3}`\n" - )); + cmd.assert() + .success() + .stderr(predicates::str::contains(format!( + "wasmer.wtf/{username}/largewasmfile@{random1}.{random2}.{random3}" + ))); } // Runs a full integration test to test that the flow wasmer init - cargo build - // wasmer publish is working #[test] fn wasmer_init_publish() { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return; - } - let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let tempdir = tempfile::tempdir().unwrap(); let path = tempdir.path(); @@ -96,8 +135,6 @@ fn wasmer_init_publish() { let s = std::fs::read_to_string(path.join("randomversion").join("wasmer.toml")).unwrap(); - println!("{s}"); - // publish let mut cmd = std::process::Command::new(get_wasmer_path()); cmd.arg("publish") @@ -115,18 +152,13 @@ fn wasmer_init_publish() { let assert = cmd.assert(); - assert.success().stdout(format!( - "🚀 Successfully published package `{username}/randomversion@{random1}.{random2}.{random3}`\n" - )); + assert.success().stderr(predicates::str::contains(format!( + "wasmer.wtf/{username}/randomversion@{random1}.{random2}.{random3}" + ))); } #[test] fn wasmer_publish_and_run() { - // Only run this test in the CI - if std::env::var("GITHUB_TOKEN").is_err() { - return; - } - let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").ok(); let tempdir = tempfile::tempdir().unwrap(); let path = tempdir.path(); @@ -166,9 +198,11 @@ fn wasmer_publish_and_run() { cmd.arg("--token").arg(token); } - cmd.assert().success().stdout(format!( - "🚀 Successfully published package `{package_name}`\n" - )); + cmd.assert() + .success() + .stderr(predicates::str::contains(format!( + "wasmer.wtf/{package_name}" + ))); let assert = std::process::Command::new(get_wasmer_path()) .arg("run")