Skip to content

Commit feedff9

Browse files
feat: add e2e tests to check different examples are working properly (#134)
* feat: add e2e tests to check different examples are working properly * feat: make e2e timeouts configurable on the CI * feat: use wws release binary when available on e2e tests * feat: add ruby and python e2e tests. Reuse wws release from cache * format: improve E2E_WAITING_TIME load Co-authored-by: Rafael Fernández López <[email protected]> --------- Co-authored-by: Rafael Fernández López <[email protected]>
1 parent 40c6405 commit feedff9

File tree

6 files changed

+233
-10
lines changed

6 files changed

+233
-10
lines changed

.github/workflows/build.yml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ jobs:
2626
run: cargo fmt --check
2727
- name: Clippy
2828
run: cargo clippy -- -D warnings
29-
test:
29+
build:
3030
strategy:
3131
fail-fast: false
3232
matrix:
33-
os: [ubuntu-latest, windows-latest]
33+
os: [ubuntu-latest, macos-latest, windows-latest]
3434
runs-on: ${{ matrix.os }}
3535
steps:
3636
- uses: actions/checkout@v3
@@ -42,11 +42,13 @@ jobs:
4242
~/.cargo/git
4343
target
4444
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
45+
- name: Install Wasm32-wasi target
46+
run: rustup target add wasm32-wasi
47+
- name: Build Rust examples
48+
working-directory: ./examples
49+
run: make all
50+
- name: Build wws on release mode
51+
if: steps.check_file_release.outputs.files_exists != 'true'
52+
run: cargo build --verbose --release
4553
- name: Test
46-
run: cargo test --workspace --exclude wasm-workers-quick-js-engine
47-
build:
48-
runs-on: ubuntu-latest
49-
steps:
50-
- uses: actions/checkout@v3
51-
- name: Build
52-
run: cargo build --verbose
54+
run: cargo test --workspace --exclude wasm-workers-quick-js-engine -- --show-output

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ wws-router = { workspace = true }
3333
wws-server = { workspace = true }
3434
wws-runtimes-manager = { workspace = true }
3535

36+
[dev-dependencies]
37+
reqwest = { version = "0.11", features = ["blocking"] }
38+
3639
[target.x86_64-unknown-linux-musl.dependencies]
3740
openssl = { version = "=0.10.48", features = ["vendored"] }
3841

examples/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ pdf-create:
2020
cargo build --target wasm32-wasi --release && \
2121
mv target/wasm32-wasi/release/pdf-create.wasm ./index.wasm
2222

23-
all: rust-basic rust-kv rust-params pdf-create
23+
all: rust-basic rust-kv rust-params

examples/ruby-basic/.wws.toml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
version = 1
2+
3+
[[repositories]]
4+
name = "wasmlabs"
5+
url = "https://workers.wasmlabs.dev/repository/v1/index.toml"
6+
7+
[[repositories.runtimes]]
8+
name = "ruby"
9+
version = "3.2.0+20230215-1"
10+
tags = [
11+
"latest",
12+
"3.2",
13+
"3.2.0",
14+
]
15+
status = "active"
16+
extensions = ["rb"]
17+
args = [
18+
"--",
19+
"/src/index.rb",
20+
]
21+
22+
[repositories.runtimes.binary]
23+
url = "https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/ruby%2F3.2.0%2B20230215-1349da9/ruby-3.2.0.wasm"
24+
filename = "ruby.wasm"
25+
26+
[repositories.runtimes.binary.checksum]
27+
type = "sha256"
28+
value = "abe348fba157a756f86194be445c77c99e8ed64ca76495ea07ed984f09eb66ae"
29+
30+
[repositories.runtimes.polyfill]
31+
url = "https://workers.wasmlabs.dev/repository/v1/files/ruby/3-1/poly.rb"
32+
filename = "poly.rb"
33+
34+
[repositories.runtimes.polyfill.checksum]
35+
type = "sha256"
36+
value = "449855a5d315879ab0ad830aa6a3f689e68fed4490617ea03efc77c9da64f630"
37+
38+
[repositories.runtimes.wrapper]
39+
url = "https://workers.wasmlabs.dev/repository/v1/files/ruby/3-1/wrapper.txt"
40+
filename = "wrapper.txt"
41+
42+
[repositories.runtimes.wrapper.checksum]
43+
type = "sha256"
44+
value = "6d808b4747cf30f82665a38a47e1176513bbdd6ad558c09db03d719e33ad2da0"

tests/e2e.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#[cfg(test)]
2+
mod test {
3+
use std::path::PathBuf;
4+
use std::process::{Child, Command, Stdio};
5+
use std::{env, io, thread, time};
6+
7+
#[cfg(not(target_os = "windows"))]
8+
fn get_wws_path() -> PathBuf {
9+
let path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
10+
11+
// Use release when it's available
12+
let wws_path = if path.join("target/release/wws").exists() {
13+
path.join("target/release/wws")
14+
} else {
15+
path.join("target/debug/wws")
16+
};
17+
18+
println!("[E2E] Running wws from {}", wws_path.display());
19+
20+
wws_path
21+
}
22+
23+
#[cfg(target_os = "windows")]
24+
fn get_wws_path() -> PathBuf {
25+
let path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
26+
27+
// Use release when it's available
28+
let wws_path = if path.join("target/release/wws.exe").exists() {
29+
path.join("target/release/wws.exe")
30+
} else {
31+
path.join("target/debug/wws.exe")
32+
};
33+
34+
println!("[E2E] Running wws from {}", wws_path.display());
35+
36+
wws_path
37+
}
38+
39+
fn run(example_path: &str) -> io::Result<Child> {
40+
let path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
41+
let example_path = path.join("examples").join(example_path);
42+
let wws_path = get_wws_path();
43+
44+
// Install missing runtimes
45+
println!("[E2E] Installing missing runtimes");
46+
Command::new(&wws_path)
47+
.current_dir(&example_path)
48+
.args(["runtimes", "install"])
49+
.stdout(Stdio::inherit())
50+
.stderr(Stdio::inherit())
51+
.status()?;
52+
53+
// Run the example
54+
println!("[E2E] Running the service");
55+
Command::new(&wws_path).arg(&example_path).spawn()
56+
}
57+
58+
fn sleep_for(seconds: u64) {
59+
thread::sleep(time::Duration::from_secs(seconds));
60+
}
61+
62+
fn request_body(url: &str) -> Result<String, reqwest::Error> {
63+
reqwest::blocking::get(url)?.text()
64+
}
65+
66+
// Check the examples/js-json works
67+
fn run_end_to_end_test(example: &str, waiting_seconds: u64, url: &str, expected_text: &str) {
68+
println!("[E2E] Running example: {example}");
69+
70+
let mut child = run(example).expect("Failed to execute command");
71+
72+
sleep_for(waiting_seconds);
73+
74+
let body = match request_body(url) {
75+
Ok(body) => body,
76+
Err(err) => {
77+
eprintln!("[E2E] Error getting the body from the request to {url}");
78+
eprintln!("[E2E] Error: {}", err);
79+
String::new()
80+
}
81+
};
82+
83+
println!("[E2E] Body content: {body}");
84+
85+
println!("[E2E] Stopping wws process [{}]", &child.id());
86+
child.kill().expect("Error stopping wws");
87+
88+
// Test
89+
assert!(body.contains(expected_text));
90+
}
91+
92+
#[test]
93+
// Use this approach to run tests sequentially
94+
fn test_end_to_end() {
95+
// Allow configuring waiting times. It avoids having long waiting times
96+
// in development, while making it configurable in the CI
97+
let global_timeout =
98+
env::var("E2E_WAITING_TIME").map_or(None, |str| str.parse::<u64>().ok());
99+
100+
// env (Result(String)) -> map ()
101+
102+
let tests = [
103+
(
104+
"rust-basic",
105+
global_timeout.unwrap_or(5),
106+
"http://localhost:8080/basic",
107+
"This page was generated by a Wasm module built from Rust",
108+
),
109+
(
110+
"rust-kv",
111+
global_timeout.unwrap_or(5),
112+
"http://localhost:8080/kv",
113+
"Counter: 0",
114+
),
115+
(
116+
"rust-params",
117+
global_timeout.unwrap_or(5),
118+
"http://localhost:8080/thisisatest",
119+
"thisisatest",
120+
),
121+
(
122+
"js-basic",
123+
global_timeout.unwrap_or(5),
124+
"http://localhost:8080",
125+
"This page was generated by a JavaScript file",
126+
),
127+
(
128+
"js-json",
129+
global_timeout.unwrap_or(5),
130+
"http://localhost:8080/handler",
131+
"This message comes from an environment variable",
132+
),
133+
(
134+
"js-params",
135+
global_timeout.unwrap_or(10),
136+
"http://localhost:8080/thisisatest",
137+
"thisisatest",
138+
),
139+
(
140+
"python-basic",
141+
global_timeout.unwrap_or(20),
142+
"http://localhost:8080/",
143+
"This page was generated by a Python script",
144+
),
145+
(
146+
"python-mount",
147+
global_timeout.unwrap_or(20),
148+
"http://localhost:8080/",
149+
"This page was loaded from a mounted file",
150+
),
151+
(
152+
"ruby-basic",
153+
global_timeout.unwrap_or(20),
154+
"http://localhost:8080/",
155+
"This page was generated by a Ruby script",
156+
),
157+
];
158+
159+
for (example, waiting_seconds, url, expected_text) in tests {
160+
run_end_to_end_test(example, waiting_seconds, url, expected_text);
161+
}
162+
}
163+
}

0 commit comments

Comments
 (0)