Skip to content

Commit 5e4ac59

Browse files
Use latest conformance-tests to leverage libtest-mimic and run in parallel
- Set unique port for each run - Set unique ctr run ID for each run Signed-off-by: Kate Goldenring <[email protected]>
1 parent cecce6c commit 5e4ac59

File tree

3 files changed

+90
-69
lines changed

3 files changed

+90
-69
lines changed

Cargo.lock

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

conformance-tests/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ homepage.workspace = true
99

1010
[dependencies]
1111
anyhow = "1.0"
12-
conformance-tests = { git = "https://github.com/fermyon/conformance-tests", ref = "c19e5cf54b7586829e923bd2091314e4d473f4f5" }
12+
conformance-tests = { git = "https://github.com/fermyon/conformance-tests", ref = "db0ee32a825561d35f884a246e1d390134d78823" }
1313
log = "0.4"
1414
nix = "0.26"
15-
test-environment = { git = "https://github.com/fermyon/conformance-tests", ref = "c19e5cf54b7586829e923bd2091314e4d473f4f5" }
15+
test-environment = { git = "https://github.com/fermyon/conformance-tests", ref = "db0ee32a825561d35f884a246e1d390134d78823" }

conformance-tests/src/main.rs

Lines changed: 86 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
hash::{DefaultHasher, Hash, Hasher},
23
path::{Path, PathBuf},
34
process::{Command, Stdio},
45
};
@@ -12,69 +13,67 @@ use test_environment::{
1213
};
1314

1415
fn main() {
15-
let tests_dir = conformance_tests::download_tests().unwrap();
1616
let mut args = std::env::args().skip(1);
17-
let spin_binary = &args
17+
let spin_binary: std::path::PathBuf = args
1818
.next()
19-
.expect("expected first arg to be path to Spin binary");
20-
let ctr_binary = &args
19+
.expect("expected first arg to be path to Spin binary")
20+
.into();
21+
let ctr_binary: std::path::PathBuf = args
2122
.next()
22-
.expect("expected second arg to be path to ctr binary");
23+
.expect("expected second arg to be path to ctr binary")
24+
.into();
25+
conformance_tests::run_tests(move |test| run_test(test, &spin_binary, &ctr_binary)).unwrap();
26+
}
2327

24-
'test: for test in conformance_tests::tests_iter(&tests_dir).unwrap() {
25-
if test.name.starts_with("tcp") {
26-
// Skip TCP tests for now as shim cannot create sockets
27-
continue;
28-
}
29-
println!("running test: {}", test.name);
30-
let mut services = vec!["registry".into()];
31-
for precondition in &test.config.preconditions {
32-
match precondition {
33-
conformance_tests::config::Precondition::HttpEcho => {
34-
services.push("http-echo".into());
35-
}
36-
conformance_tests::config::Precondition::KeyValueStore(k) => {
37-
if k.label != "default" {
38-
panic!("unsupported label: {}", k.label);
39-
}
40-
}
41-
conformance_tests::config::Precondition::TcpEcho => {
42-
services.push("tcp-echo".into());
43-
}
28+
fn run_test(
29+
test: conformance_tests::Test,
30+
spin_binary: &std::path::Path,
31+
ctr_binary: &std::path::Path,
32+
) -> anyhow::Result<()> {
33+
println!("running test: {}", test.name);
34+
let mut services = vec!["registry".into()];
35+
for precondition in &test.config.preconditions {
36+
match precondition {
37+
conformance_tests::config::Precondition::HttpEcho => {
38+
services.push("http-echo".into());
4439
}
45-
}
46-
let env_config = SpinShim::config(
47-
ctr_binary.into(),
48-
spin_binary.into(),
49-
test.name.clone(),
50-
test_environment::services::ServicesConfig::new(services).unwrap(),
51-
);
52-
let mut env = TestEnvironment::up(env_config, move |e| {
53-
let mut manifest =
54-
test_environment::manifest_template::EnvTemplate::from_file(&test.manifest)
55-
.unwrap();
56-
manifest.substitute(e, |_| None).unwrap();
57-
e.write_file("spin.toml", manifest.contents())?;
58-
e.copy_into(&test.component, test.component.file_name().unwrap())?;
59-
Ok(())
60-
})
61-
.unwrap();
62-
for invocation in test.config.invocations {
63-
let conformance_tests::config::Invocation::Http(mut invocation) = invocation;
64-
invocation.request.substitute_from_env(&mut env).unwrap();
65-
let shim = env.runtime_mut();
66-
if let Err(e) = invocation.run(|request| shim.make_http_request(request)) {
67-
println!("❌ test failed: {}", test.name);
68-
println!("error: {}", e);
69-
for e in e.chain() {
70-
println!("\t{}", e);
40+
conformance_tests::config::Precondition::KeyValueStore(k) => {
41+
if k.label != "default" {
42+
panic!("unsupported label: {}", k.label);
7143
}
72-
73-
continue 'test;
44+
}
45+
conformance_tests::config::Precondition::TcpEcho => {
46+
services.push("tcp-echo".into());
47+
}
48+
conformance_tests::config::Precondition::Sqlite => {}
49+
conformance_tests::config::Precondition::Redis => {
50+
services.push("redis".into());
7451
}
7552
}
76-
println!("✅ test passed: {}", test.name);
7753
}
54+
let env_config = SpinShim::config(
55+
ctr_binary.into(),
56+
spin_binary.into(),
57+
test.name.clone(),
58+
test_environment::services::ServicesConfig::new(services).unwrap(),
59+
&test.name,
60+
);
61+
let mut env = TestEnvironment::up(env_config, move |e| {
62+
let mut manifest =
63+
test_environment::manifest_template::EnvTemplate::from_file(&test.manifest).unwrap();
64+
manifest.substitute(e, |_| None).unwrap();
65+
e.write_file("spin.toml", manifest.contents())?;
66+
e.copy_into(&test.component, test.component.file_name().unwrap())?;
67+
Ok(())
68+
})
69+
.unwrap();
70+
for invocation in test.config.invocations {
71+
let conformance_tests::config::Invocation::Http(mut invocation) = invocation;
72+
invocation.request.substitute_from_env(&mut env).unwrap();
73+
let shim = env.runtime_mut();
74+
invocation.run(|request| shim.make_http_request(request))?;
75+
}
76+
Ok(())
7877
}
7978

8079
struct SpinShim {
@@ -85,17 +84,31 @@ struct SpinShim {
8584
io_mode: IoMode,
8685
}
8786

88-
/// `ctr run` invocations require an ID that is unique to all currently running instances. Since
89-
/// only one test runs at a time, we can reuse a constant ID.
90-
const CTR_RUN_ID: &str = "run-id";
87+
fn hash<T>(obj: T) -> u64
88+
where
89+
T: Hash,
90+
{
91+
let mut hasher = DefaultHasher::new();
92+
obj.hash(&mut hasher);
93+
hasher.finish()
94+
}
95+
96+
/// Uses a track to get a random unused port
97+
fn get_available_port() -> anyhow::Result<u16> {
98+
Ok(std::net::TcpListener::bind("localhost:0")?
99+
.local_addr()?
100+
.port())
101+
}
91102

92103
impl SpinShim {
93104
pub fn config(
94105
ctr_binary: PathBuf,
95106
spin_binary: PathBuf,
96107
oci_image: String,
97108
services_config: ServicesConfig,
109+
test_id: &str,
98110
) -> TestEnvironmentConfig<SpinShim> {
111+
let ctr_run_id = hash(test_id).to_string();
99112
TestEnvironmentConfig {
100113
services_config,
101114
create_runtime: Box::new(move |env| {
@@ -107,7 +120,7 @@ impl SpinShim {
107120
);
108121
SpinShim::registry_push(&spin_binary, &oci_image, env)?;
109122
SpinShim::image_pull(&ctr_binary, &oci_image)?;
110-
SpinShim::start(&ctr_binary, env, &oci_image, CTR_RUN_ID)
123+
SpinShim::start(&ctr_binary, env, &oci_image, &ctr_run_id)
111124
}),
112125
}
113126
}
@@ -125,12 +138,12 @@ impl SpinShim {
125138
}
126139

127140
pub fn image_pull(ctr_binary_path: &Path, image: &str) -> anyhow::Result<()> {
128-
Command::new(ctr_binary_path)
141+
let output = Command::new(ctr_binary_path)
129142
.args(["image", "pull"])
130143
.arg(image)
131144
.output()
132145
.context("failed to pull spin app with 'ctr'")?;
133-
// TODO: assess output
146+
anyhow::ensure!(output.status.success(), "pulling image failed");
134147
Ok(())
135148
}
136149

@@ -141,13 +154,21 @@ impl SpinShim {
141154
image: &str,
142155
ctr_run_id: &str,
143156
) -> anyhow::Result<Self> {
144-
// TODO: consider enabling configuring a port
145-
let port = 80;
157+
let port = get_available_port().context("no available port")?;
158+
let listen_adress_env = format!("SPIN_HTTP_LISTEN_ADDR=0.0.0.0:{}", port);
146159
let mut ctr_cmd = std::process::Command::new(ctr_binary_path);
147160
let child = ctr_cmd
148161
.arg("run")
149-
.args(["--rm", "--net-host", "--runtime", "io.containerd.spin.v2"])
162+
.args([
163+
"--rm",
164+
"--net-host",
165+
"--runtime",
166+
"io.containerd.spin.v2",
167+
"--env",
168+
])
169+
.arg(listen_adress_env)
150170
.arg(image)
171+
// `ctr run` invocations require an ID that is unique to all currently running instances
151172
.arg(ctr_run_id)
152173
// The container runtime expects at least one argument to the container
153174
.arg("bogus-arg")
@@ -199,9 +220,9 @@ impl SpinShim {
199220
)
200221
}
201222

202-
/// Make an HTTP request against Spin
223+
/// Make an HTTP request against the shim.
203224
///
204-
/// Will fail if Spin has already exited or if the io mode is not HTTP
225+
/// Will fail if the shim has already exited.
205226
pub fn make_http_request(&mut self, request: Request<'_, String>) -> anyhow::Result<Response> {
206227
let IoMode::Http(port) = self.io_mode;
207228
if let Some(status) = self.try_wait()? {

0 commit comments

Comments
 (0)