Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+259
View File
@@ -0,0 +1,259 @@
//! 逐调用取消与校验失败必须完成自己的清理,不等待另一个调用或阻塞任务。
use super::{CONTRACT, Directory, ENTRY, EXECUTOR, bundle, call, pid};
use dever_runtime::{
task::{Limits, Runtime, Timed},
wire::json::Json,
worker::{self, Setting},
};
use std::{fs, path::PathBuf, process::Command, time::Duration};
#[test]
fn worker_validation_cancellation_and_cleanup_are_owned() {
let _execution = EXECUTOR.lock().unwrap();
let directory = Directory::new();
let fixture = directory.0.join("fixture");
let source = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../../test/rust/runtime/worker/fixture.rs");
let built = Command::new("rustup")
.args(["run", "1.95.0", "rustc", "--edition=2024", "-O"])
.arg(source)
.arg("-o")
.arg(&fixture)
.output()
.unwrap();
assert!(
built.status.success(),
"{}",
String::from_utf8_lossy(&built.stderr)
);
let runner = directory.0.join("runner");
fs::copy(std::env::current_exe().unwrap(), &runner).unwrap();
let result = Command::new(runner)
.args(["--exact", "lifecycle::owned_lifecycle_case", "--nocapture"])
.env_clear()
.env("DEVER_LIFECYCLE_FIXTURE", fixture)
.output()
.unwrap();
assert!(
result.status.success(),
"{}\n{}",
String::from_utf8_lossy(&result.stdout),
String::from_utf8_lossy(&result.stderr)
);
}
#[test]
fn owned_lifecycle_case() {
let Some(fixture) = std::env::var_os("DEVER_LIFECYCLE_FIXTURE") else {
return;
};
let bundle = bundle(fs::read(&fixture).unwrap());
fs::remove_file(fixture).unwrap();
let runtime = Runtime::new(Limits {
threads: 2,
workers: 1,
tasks: 32,
})
.unwrap();
runtime
.run(async |scope| {
let first = pid(call(scope, bundle, "echo").await.unwrap());
let held = worker::call(
scope,
bundle,
ENTRY,
CONTRACT,
&Setting::empty(),
"echo",
Json::parse("{}").unwrap(),
)
.await
.unwrap();
let queued = scope
.spawn(move |child| async move { call(&child, bundle, "echo").await })
.unwrap();
let stopped =
tokio::time::timeout(Duration::from_millis(300), queued.timeout(30)).await;
assert!(matches!(stopped, Ok(Ok(Timed::Expired(None)))));
assert_eq!(first, pid(held.resolve(Ok).await.unwrap()));
let held = worker::call(
scope,
bundle,
ENTRY,
CONTRACT,
&Setting::empty(),
"echo",
Json::parse("{}").unwrap(),
)
.await
.unwrap();
let queued = scope
.spawn(move |child| async move { call(&child, bundle, "echo").await })
.unwrap();
tokio::time::sleep(Duration::from_millis(30)).await;
let failed = held
.resolve::<()>(|_| Err("invalid typed payload".into()))
.await
.unwrap_err();
assert!(failed.contains("invalid typed payload"));
assert!(!PathBuf::from(format!("/proc/{first}")).exists());
assert!(
queued
.wait()
.await
.unwrap()
.err()
.unwrap()
.contains("queued")
);
let second = pid(call(scope, bundle, "echo").await.unwrap());
assert_ne!(first, second);
let held = worker::call(
scope,
bundle,
ENTRY,
CONTRACT,
&Setting::empty(),
"echo",
Json::parse("{}").unwrap(),
)
.await
.unwrap();
let queued = scope
.spawn(move |child| async move { call(&child, bundle, "echo").await })
.unwrap();
tokio::time::sleep(Duration::from_millis(30)).await;
drop(held);
let failed = tokio::time::timeout(Duration::from_secs(3), queued.wait())
.await
.unwrap()
.unwrap()
.err()
.unwrap();
assert!(failed.contains("queued"));
assert!(!PathBuf::from(format!("/proc/{second}")).exists());
let third = pid(call(scope, bundle, "echo").await.unwrap());
assert_ne!(second, third);
let panicked = scope
.spawn(move |child| async move {
worker::call(
&child,
bundle,
ENTRY,
CONTRACT,
&Setting::empty(),
"echo",
Json::parse("{}").unwrap(),
)
.await
.unwrap()
.resolve::<()>(|_| panic!("typed decoder panicked"))
.await
})
.unwrap();
assert!(matches!(
tokio::time::timeout(Duration::from_secs(3), panicked.wait()).await,
Ok(Err(dever_runtime::task::Error::Panicked))
));
assert!(!PathBuf::from(format!("/proc/{third}")).exists());
worker::finish(scope, Ok(())).await.unwrap();
})
.unwrap();
runtime
.run(async |scope| {
#[derive(serde::Deserialize)]
struct Config {
#[serde(rename = "token")]
_token: dever_runtime::value::secret::Secret,
}
let document = dever_runtime::adapter::Document::parse(
r#"{"adapter":{"demo.test":{"setting":{"token":"sensitive\"\\雪"}}}}"#.into(),
)
.unwrap();
let schemas = [dever_runtime::adapter::Schema {
name: "demo.test",
implementations: &["default"],
}];
let selected = document.select(&schemas).unwrap();
let setting = selected[0].worker_setting::<Config>().unwrap();
let input = Json::parse("{}").unwrap();
let process = pid(worker::call(
scope,
bundle,
ENTRY,
CONTRACT,
&setting,
"echo",
input.clone(),
)
.await
.unwrap()
.resolve(Ok)
.await
.unwrap());
let error = worker::call(scope, bundle, ENTRY, CONTRACT, &setting, "bad", input)
.await
.err()
.unwrap();
assert!(!error.contains("sensitive"));
assert!(!PathBuf::from(format!("/proc/{process}")).exists());
worker::finish(scope, Ok(())).await.unwrap();
})
.unwrap();
runtime
.run(async |scope| {
let (started, ready) = tokio::sync::oneshot::channel();
let (release, receive) = std::sync::mpsc::channel();
let blocking = scope
.spawn_sync(move || {
started.send(()).unwrap();
receive.recv().unwrap();
})
.unwrap();
ready.await.unwrap();
let queued = scope
.spawn(move |child| async move { call(&child, bundle, "echo").await })
.unwrap();
let cancelled =
tokio::time::timeout(Duration::from_millis(300), queued.timeout(30)).await;
release.send(()).unwrap();
blocking.wait().await.unwrap();
assert!(matches!(cancelled, Ok(Ok(Timed::Expired(None)))));
worker::finish(scope, Ok(())).await.unwrap();
})
.unwrap();
runtime
.run(async |scope| {
let process = pid(call(scope, bundle, "echo").await.unwrap());
let hanging = scope
.spawn(move |child| async move { call(&child, bundle, "ignore").await })
.unwrap();
let result = tokio::time::timeout(Duration::from_secs(3), hanging.timeout(50))
.await
.unwrap()
.unwrap();
assert!(matches!(result, Timed::Expired(None)));
assert!(!PathBuf::from(format!("/proc/{process}")).exists());
worker::finish(scope, Ok(())).await.unwrap();
})
.unwrap();
runtime
.run(async |scope| {
let process = pid(call(scope, bundle, "shutdown_bad").await.unwrap());
let error = worker::finish::<()>(scope, Err("primary failure".into()))
.await
.unwrap_err();
assert!(
error.contains("primary failure") && error.contains("shutdown"),
"{error}"
);
assert!(!PathBuf::from(format!("/proc/{process}")).exists());
})
.unwrap();
}