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

+194
View File
@@ -0,0 +1,194 @@
use crate::{
adapter::Document,
database::{Binding, Database, Error, Executor, Options, Parameter, Registry},
job::{self, Claim, Execution, Policy, Submission},
task::{Runtime, Scope},
wire::json::Json,
};
use futures_util::FutureExt;
use std::{
panic::AssertUnwindSafe,
path::PathBuf,
sync::{Arc, LazyLock},
time::Duration,
};
mod heartbeat;
mod lease;
mod queue;
mod schedule;
mod workers;
const NOW: i64 = 1_700_000_000_000;
#[derive(Clone)]
struct Case {
database: Database,
schema: String,
directory: PathBuf,
}
impl Case {
async fn registry(&self, scope: &Scope<'_>) -> Arc<Registry> {
Registry::load(
&self.directory.join("setting.json"),
&[Binding {
storage: crate::database::Storage::Global,
component: "demo",
database: Some("default"),
table: job::schema::TABLE,
schema: job::schema::SQL,
plan: None,
references: &[],
}],
scope,
)
.await
.unwrap()
}
async fn executor(&self, scope: &Scope<'_>) -> Executor {
let mut executor = self.database.executor().await.unwrap();
executor
.query(
scope,
"SELECT set_config('search_path',$1,false)",
vec![Parameter::Text(self.schema.clone())],
1,
|row| row.get::<_, String>(0),
)
.await
.unwrap();
executor
}
async fn count(&self, scope: &Scope<'_>, sql: &'static str) -> i64 {
self.executor(scope)
.await
.query(scope, sql, vec![], 1, |row| row.get::<_, i64>(0))
.await
.unwrap()[0]
}
}
fn fixture(check: impl AsyncFnOnce(&Case, &Scope<'_>)) {
let path =
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../../config/setting.json");
let document = Document::load(&path).expect("cannot read PostgreSQL test settings");
let root: serde_json::Value = document.decode().expect("invalid PostgreSQL test settings");
let value = root
.get("database")
.and_then(|database| database.get("postgres_test"))
.expect("database.postgres_test must select an isolated test database");
let mut options: Options = serde_json::from_value(value.clone())
.unwrap_or_else(|_| panic!("invalid PostgreSQL test options"));
assert_eq!(options.driver, "postgres");
options.max_connections = 8;
options.wait_timeout_ms = 1000;
options.io_timeout_ms = 5000;
Runtime::new(Default::default())
.unwrap()
.run(async |scope| {
let database = Database::open(std::path::Path::new("."), options, scope)
.await
.unwrap();
let schema = format!("dever_job_test_{}", job::identifier().unwrap());
let directory = std::env::temp_dir().join(&schema);
std::fs::create_dir(&directory).unwrap();
let case = Case {
database,
schema,
directory,
};
let mut owner = case.database.executor().await.unwrap();
owner
.postgres_operation(async |client| {
client
.batch_execute(&format!("CREATE SCHEMA {}", case.schema))
.await
.map_err(Error::from)
})
.await
.unwrap();
let outcome = AssertUnwindSafe(async {
use std::{
io::Write,
os::unix::fs::{OpenOptionsExt, PermissionsExt},
};
std::fs::set_permissions(&case.directory, std::fs::Permissions::from_mode(0o700))
.unwrap();
let mut connection = value.clone();
connection["max_connections"] = 8.into();
let url = connection["url"].as_str().unwrap();
assert!(
url.parse::<tokio_postgres::Config>()
.unwrap()
.get_options()
.is_none()
);
let separator = if url.contains('?') { '&' } else { '?' };
connection["url"] =
format!("{url}{separator}options=-csearch_path%3D{}", case.schema).into();
let mut settings = std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.mode(0o600)
.open(case.directory.join("setting.json"))
.unwrap();
settings
.write_all(
&serde_json::to_vec(
&serde_json::json!({"database":{"default":connection}}),
)
.unwrap(),
)
.unwrap();
let mut executor = case.executor(scope).await;
executor
.schema(scope, job::schema::TABLE, job::schema::SQL)
.await
.unwrap();
executor
.schema(scope, job::schema::TABLE, job::schema::SQL)
.await
.unwrap();
drop(executor);
tokio::time::timeout(Duration::from_secs(30), check(&case, scope))
.await
.expect("PostgreSQL Job test deadline exceeded");
})
.catch_unwind()
.await;
let cleanup = owner
.postgres_operation(async |client| {
client
.batch_execute(&format!("DROP SCHEMA {} CASCADE", case.schema))
.await
.map_err(Error::from)
})
.await;
case.database.close();
std::fs::remove_dir_all(&case.directory).unwrap();
cleanup.expect("PostgreSQL Job test schema cleanup failed");
if let Err(panic) = outcome {
std::panic::resume_unwind(panic);
}
})
.unwrap();
}
fn submission(key: &str) -> Submission<'_> {
static PAYLOAD: LazyLock<Json> = LazyLock::new(|| Json::parse(r#"{"number":1}"#).unwrap());
Submission {
target: "demo.account.publish",
payload: Some(&PAYLOAD),
schema: "schema-1",
execution: &Execution::System { tenant: None },
key,
policy: Policy {
retries: 2,
timeout_ms: 50,
},
at: NOW,
}
}