|
1 |
| -use std::collections::HashMap; |
2 |
| -use std::env; |
3 |
| -use std::ops::Deref; |
4 |
| -use std::path::Path; |
5 |
| -use std::sync::{Arc, LazyLock, Once}; |
6 |
| -use std::time::Duration; |
7 |
| - |
8 |
| -use anyhow::{Result, anyhow, bail}; |
9 |
| -use futures::stream::{FuturesUnordered, TryStreamExt}; |
10 |
| -use tokio::fs; |
11 |
| -use tokio::sync::Mutex; |
12 |
| -use wasm_compose::composer::ComponentComposer; |
13 |
| -use wasmtime::component::{Component, Linker, ResourceTable}; |
14 |
| -use wasmtime::{Config, Engine, Store}; |
15 |
| -use wasmtime_wasi::p2::WasiCtxBuilder; |
16 |
| - |
17 |
| -use super::{Ctx, sleep}; |
18 |
| - |
19 |
| -pub fn init_logger() { |
20 |
| - static ONCE: Once = Once::new(); |
21 |
| - ONCE.call_once(env_logger::init); |
22 |
| -} |
23 |
| - |
24 |
| -pub fn config() -> Config { |
25 |
| - init_logger(); |
26 |
| - |
27 |
| - let mut config = Config::new(); |
28 |
| - if env::var_os("MIRI_TEST_CWASM_DIR").is_some() { |
29 |
| - config.target("pulley64").unwrap(); |
30 |
| - config.memory_reservation(1 << 20); |
31 |
| - config.memory_guard_size(0); |
32 |
| - config.signals_based_traps(false); |
33 |
| - } else { |
34 |
| - config.cranelift_debug_verifier(true); |
35 |
| - } |
36 |
| - config.wasm_component_model(true); |
37 |
| - config.wasm_component_model_async(true); |
38 |
| - config.wasm_component_model_async_builtins(true); |
39 |
| - config.wasm_component_model_async_stackful(true); |
40 |
| - config.wasm_component_model_error_context(true); |
41 |
| - config.async_support(true); |
42 |
| - config |
43 |
| -} |
44 |
| - |
45 | 1 | pub async fn sleep(duration: std::time::Duration) {
|
46 | 2 | if cfg!(miri) {
|
47 | 3 | // TODO: We should be able to use `tokio::time::sleep` here, but as of
|
@@ -95,189 +51,3 @@ pub async fn sleep(duration: std::time::Duration) {
|
95 | 51 | tokio::time::sleep(duration).await;
|
96 | 52 | }
|
97 | 53 | }
|
98 |
| - |
99 |
| -/// Compose two components |
100 |
| -/// |
101 |
| -/// a is the "root" component, and b is composed into it |
102 |
| -#[allow(unused)] |
103 |
| -async fn compose(a: &[u8], b: &[u8]) -> Result<Vec<u8>> { |
104 |
| - let dir = tempfile::tempdir()?; |
105 |
| - |
106 |
| - let a_file = dir.path().join("a.wasm"); |
107 |
| - fs::write(&a_file, a).await?; |
108 |
| - |
109 |
| - let b_file = dir.path().join("b.wasm"); |
110 |
| - fs::write(&b_file, b).await?; |
111 |
| - |
112 |
| - ComponentComposer::new( |
113 |
| - &a_file, |
114 |
| - &wasm_compose::config::Config { |
115 |
| - dir: dir.path().to_owned(), |
116 |
| - definitions: vec![b_file.to_owned()], |
117 |
| - ..Default::default() |
118 |
| - }, |
119 |
| - ) |
120 |
| - .compose() |
121 |
| -} |
122 |
| - |
123 |
| -pub async fn make_component(engine: &Engine, components: &[&str]) -> Result<Component> { |
124 |
| - fn cwasm_name(components: &[&str]) -> Result<String> { |
125 |
| - if components.is_empty() { |
126 |
| - Err(anyhow!("expected at least one path")) |
127 |
| - } else { |
128 |
| - let names = components |
129 |
| - .iter() |
130 |
| - .map(|&path| { |
131 |
| - let path = Path::new(path); |
132 |
| - if let Some(name) = path.file_name() { |
133 |
| - Ok(name) |
134 |
| - } else { |
135 |
| - Err(anyhow!( |
136 |
| - "expected path with at least two components; got: {}", |
137 |
| - path.display() |
138 |
| - )) |
139 |
| - } |
140 |
| - }) |
141 |
| - .collect::<Result<Vec<_>>>()?; |
142 |
| - |
143 |
| - Ok(format!( |
144 |
| - "{}.cwasm", |
145 |
| - names |
146 |
| - .iter() |
147 |
| - .map(|name| { name.to_str().unwrap() }) |
148 |
| - .collect::<Vec<_>>() |
149 |
| - .join("+") |
150 |
| - )) |
151 |
| - } |
152 |
| - } |
153 |
| - |
154 |
| - async fn compile(engine: &Engine, components: &[&str]) -> Result<Vec<u8>> { |
155 |
| - match components { |
156 |
| - [component] => engine.precompile_component(&fs::read(component).await?), |
157 |
| - [a, b] => engine |
158 |
| - .precompile_component(&compose(&fs::read(a).await?, &fs::read(b).await?).await?), |
159 |
| - _ => Err(anyhow!("expected one or two paths")), |
160 |
| - } |
161 |
| - } |
162 |
| - |
163 |
| - async fn load(engine: &Engine, components: &[&str]) -> Result<Vec<u8>> { |
164 |
| - let cwasm_path = if let Some(cwasm_dir) = &env::var_os("MIRI_TEST_CWASM_DIR") { |
165 |
| - Some(Path::new(cwasm_dir).join(cwasm_name(components)?)) |
166 |
| - } else { |
167 |
| - None |
168 |
| - }; |
169 |
| - |
170 |
| - if let Some(cwasm_path) = &cwasm_path { |
171 |
| - if let Ok(compiled) = fs::read(cwasm_path).await { |
172 |
| - return Ok(compiled); |
173 |
| - } |
174 |
| - } |
175 |
| - |
176 |
| - if cfg!(miri) { |
177 |
| - bail!( |
178 |
| - "Running these tests with miri requires precompiled .cwasm files.\n\ |
179 |
| - Please set the `MIRI_TEST_CWASM_DIR` environment variable to the\n\ |
180 |
| - absolute path of a valid directory, then run the test(s)\n\ |
181 |
| - _without_ miri, and finally run them again _with_ miri." |
182 |
| - ) |
183 |
| - } |
184 |
| - |
185 |
| - let compiled = compile(engine, components).await?; |
186 |
| - if let Some(cwasm_path) = &cwasm_path { |
187 |
| - fs::write(cwasm_path, &compiled).await?; |
188 |
| - } |
189 |
| - Ok(compiled) |
190 |
| - } |
191 |
| - |
192 |
| - static CACHE: LazyLock<Mutex<HashMap<Vec<String>, Arc<Mutex<Option<Arc<Vec<u8>>>>>>>> = |
193 |
| - LazyLock::new(|| Mutex::new(HashMap::new())); |
194 |
| - |
195 |
| - let compiled = { |
196 |
| - let entry = CACHE |
197 |
| - .lock() |
198 |
| - .await |
199 |
| - .entry(components.iter().map(|&s| s.to_owned()).collect()) |
200 |
| - .or_insert_with(|| Arc::new(Mutex::new(None))) |
201 |
| - .clone(); |
202 |
| - |
203 |
| - let mut entry = entry.lock().await; |
204 |
| - if let Some(component) = entry.deref() { |
205 |
| - component.clone() |
206 |
| - } else { |
207 |
| - let component = Arc::new(load(engine, components).await?); |
208 |
| - *entry = Some(component.clone()); |
209 |
| - component |
210 |
| - } |
211 |
| - }; |
212 |
| - |
213 |
| - Ok(unsafe { Component::deserialize(&engine, &*compiled)? }) |
214 |
| -} |
215 |
| - |
216 |
| -#[allow(unused)] |
217 |
| -pub async fn test_run(components: &[&str]) -> Result<()> { |
218 |
| - test_run_with_count(components, 3).await |
219 |
| -} |
220 |
| - |
221 |
| -pub async fn test_run_with_count(components: &[&str], count: usize) -> Result<()> { |
222 |
| - let mut config = config(); |
223 |
| - // As of this writing, miri/pulley/epochs is a problematic combination, so |
224 |
| - // we don't test it. |
225 |
| - if env::var_os("MIRI_TEST_CWASM_DIR").is_none() { |
226 |
| - config.epoch_interruption(true); |
227 |
| - } |
228 |
| - |
229 |
| - let engine = Engine::new(&config)?; |
230 |
| - |
231 |
| - let component = make_component(&engine, components).await?; |
232 |
| - |
233 |
| - let mut linker = Linker::new(&engine); |
234 |
| - |
235 |
| - wasmtime_wasi::p2::add_to_linker_async(&mut linker)?; |
236 |
| - super::yield_host::bindings::local::local::continue_::add_to_linker::<_, Ctx>( |
237 |
| - &mut linker, |
238 |
| - |ctx| ctx, |
239 |
| - )?; |
240 |
| - super::yield_host::bindings::local::local::ready::add_to_linker::<_, Ctx>( |
241 |
| - &mut linker, |
242 |
| - |ctx| ctx, |
243 |
| - )?; |
244 |
| - super::resource_stream::bindings::local::local::resource_stream::add_to_linker::<_, Ctx>( |
245 |
| - &mut linker, |
246 |
| - |ctx| ctx, |
247 |
| - )?; |
248 |
| - sleep::local::local::sleep::add_to_linker::<_, Ctx>(&mut linker, |ctx| ctx)?; |
249 |
| - |
250 |
| - let mut store = Store::new( |
251 |
| - &engine, |
252 |
| - Ctx { |
253 |
| - wasi: WasiCtxBuilder::new().inherit_stdio().build(), |
254 |
| - table: ResourceTable::default(), |
255 |
| - continue_: false, |
256 |
| - wakers: Arc::new(std::sync::Mutex::new(None)), |
257 |
| - }, |
258 |
| - ); |
259 |
| - |
260 |
| - if env::var_os("MIRI_TEST_CWASM_DIR").is_none() { |
261 |
| - store.set_epoch_deadline(1); |
262 |
| - |
263 |
| - std::thread::spawn(move || { |
264 |
| - std::thread::sleep(Duration::from_secs(10)); |
265 |
| - engine.increment_epoch(); |
266 |
| - }); |
267 |
| - } |
268 |
| - |
269 |
| - let instance = linker.instantiate_async(&mut store, &component).await?; |
270 |
| - let yield_host = super::yield_host::bindings::YieldHost::new(&mut store, &instance)?; |
271 |
| - |
272 |
| - // Start `count` concurrent calls and then join them all: |
273 |
| - let mut futures = FuturesUnordered::new(); |
274 |
| - for _ in 0..count { |
275 |
| - futures.push(yield_host.local_local_run().call_run(&mut store)); |
276 |
| - } |
277 |
| - |
278 |
| - while let Some(()) = instance.run(&mut store, futures.try_next()).await?? { |
279 |
| - // continue |
280 |
| - } |
281 |
| - |
282 |
| - Ok(()) |
283 |
| -} |
0 commit comments