Files
core/test/rust/native/application/auth/tasks.rs
T
2026-11-03 03:32:07 +00:00

149 lines
5.3 KiB
Rust

use super::*;
#[test]
fn concurrent_enqueues_preserve_system_and_revalidated_user_identity() {
let directory = Directory::new();
let mut project = Project::load(&fixture().with_file_name("auth")).unwrap();
for source in &mut project.sources {
let text = if source.path.ends_with("app/jobs.dever") {
include_str!("../../../fixtures/job-tasks.dever").into()
} else if source.path.ends_with("api/admin/jobs.dever") {
source
.text
.replace("post job_submit =", "long post job_submit =")
.replace("cmd job_submit", "long cmd job_submit")
} else {
continue;
};
*source = dever::syntax::source::Source::new(source.id, source.path.clone(), text);
}
let program = project.check().unwrap();
let binary = build::build(
&program,
&project.sources,
"main",
&directory.0.join("tasks"),
)
.unwrap();
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let port = listener.local_addr().unwrap().port();
drop(listener);
std::fs::create_dir(directory.0.join("config")).unwrap();
let mut settings = serde_json::json!({
"http":{"host":"127.0.0.1","port":port},
"sites":{"admin":{"path":"admin","auth":"session","hosts":["fixture.test"],"origin":"https://fixture.test"}},
"database":{"default":{"type":"sqlite","path":"data/account.db","max_connections":8}},
"runtime":{"mode":"api","shutdown_ms":1000},
"auth":{"providers":{"session":{"verify":"demo.account.verify","jwtSecret":KEY,"ttlSeconds":60,"cookie":"session"}}},
"job":{"workers":1,"poll_ms":10,"lease_ms":2000}
});
std::fs::write(
directory.0.join("config/setting.json"),
settings.to_string(),
)
.unwrap();
let run = |command: &str, input: &str| {
let result = execute(&binary, command, input);
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
serde_json::from_slice::<serde_json::Value>(&result.stdout).unwrap()["data"].clone()
};
run(
"demo.account.seed",
r#"{"subject":"user","session":"valid-session"}"#,
);
run("dever.auth.owner", r#"{"site":"admin","user_id":1}"#);
let mut server = Server(Command::new(&binary).spawn().unwrap());
let deadline = Instant::now() + Duration::from_secs(5);
while TcpStream::connect(("127.0.0.1", port)).is_err() {
assert!(server.0.try_wait().unwrap().is_none());
assert!(Instant::now() < deadline);
std::thread::sleep(Duration::from_millis(10));
}
let bearer = format!(
"Authorization: Bearer {}\r\nContent-Type: application/json\r\n",
token("user", "valid-session")
);
let forged = request(
port,
"POST",
"/demo/account/admin/jobs/job_submit",
"fixture.test",
&bearer,
r#"{"subject":"forged","key":"forged","execution":{"kind":"System"}}"#,
);
assert_eq!(forged.0, 400, "{}", forged.1);
let submit = |subject: &str| {
let (status, body) = request(
port,
"POST",
"/demo/account/admin/jobs/job_submit",
"fixture.test",
&bearer,
&serde_json::json!({"subject":subject,"key":subject}).to_string(),
);
assert_eq!(status, 200, "{body}");
};
// payload 的 subject 与登录用户不同,不能用它替换请求建立的可信执行者。
submit("other-person");
run(
"demo.account.job_submit",
r#"{"subject":"system","key":"system"}"#,
);
settings["runtime"]["mode"] = "worker".into();
let worker_config = directory.0.join("worker.json");
std::fs::write(&worker_config, settings.to_string()).unwrap();
let start = || {
Server(
Command::new(&binary)
.arg("--config")
.arg(&worker_config)
.spawn()
.unwrap(),
)
};
let until = |worker: &mut Server, expected: i64| {
let deadline = Instant::now() + Duration::from_secs(10);
loop {
let actual = run("demo.account.job_count", "{}");
if actual == expected {
break;
}
assert!(worker.0.try_wait().unwrap().is_none());
assert!(
Instant::now() < deadline,
"concurrent Job did not complete: expected {expected}, got {actual}"
);
std::thread::sleep(Duration::from_millis(10));
}
};
let mut worker = start();
until(&mut worker, 13);
assert!(
Command::new("sh")
.args(["-c", "kill -TERM \"$1\"", "--", &worker.0.id().to_string()])
.status()
.unwrap()
.success()
);
assert!(worker.0.wait().unwrap().success());
submit("revoked");
run("demo.account.revoke", r#"{"id":1}"#);
run(
"demo.account.job_submit",
r#"{"subject":"system-next","key":"system-next"}"#,
);
let mut worker = start();
until(&mut worker, 19);
std::thread::sleep(Duration::from_millis(100));
assert_eq!(
run("demo.account.job_count", "{}"),
19,
"revoked User was upgraded to System"
);
}