mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-06 02:48:25 +00:00
refactor(server): gate test app state helpers
Move test-only app state constructors into the gated test_support module so release builds do not expose or link fixture helpers and secrets.
This commit is contained in:
parent
f219987f2a
commit
886173f5ad
20 changed files with 531 additions and 523 deletions
|
|
@ -111,6 +111,7 @@ chrono = { workspace = true }
|
|||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2"
|
||||
fabro-server = { path = "../fabro-server", features = ["test-support"] }
|
||||
insta = { workspace = true, features = ["filters"] }
|
||||
paste = "1"
|
||||
predicates = "3"
|
||||
|
|
|
|||
|
|
@ -23,10 +23,8 @@ use fabro_config::{RunLayer, ServerSettingsBuilder};
|
|||
use fabro_server::auth::GithubEndpoints;
|
||||
use fabro_server::ip_allowlist::IpAllowlistConfig;
|
||||
use fabro_server::jwt_auth::resolve_auth_mode_with_lookup;
|
||||
use fabro_server::server::{
|
||||
RouterOptions, build_router_with_options,
|
||||
create_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env,
|
||||
};
|
||||
use fabro_server::server::{RouterOptions, build_router_with_options};
|
||||
use fabro_server::test_support::test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env;
|
||||
use fabro_test::{GitHubAppState, TestContext, apply_test_isolation};
|
||||
use serde_json::Value;
|
||||
use tokio::net::TcpListener;
|
||||
|
|
@ -92,7 +90,7 @@ impl RealAuthHarness {
|
|||
if let Some(token) = dev_token.clone() {
|
||||
secrets.insert("FABRO_DEV_TOKEN".to_string(), token);
|
||||
}
|
||||
let state = create_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
let state = test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
settings,
|
||||
RunLayer::default(),
|
||||
5,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ description = "HTTP server for Fabro pipelines"
|
|||
[lib]
|
||||
doctest = false
|
||||
|
||||
[features]
|
||||
test-support = []
|
||||
|
||||
[[test]]
|
||||
name = "it"
|
||||
path = "tests/it/main.rs"
|
||||
required-features = ["test-support"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
|
|
|||
|
|
@ -1243,7 +1243,6 @@ mod tests {
|
|||
use crate::auth::{self, AuthCode, AuthErrorCode, RefreshToken};
|
||||
use crate::jwt_auth::{AuthMode, ConfiguredAuth};
|
||||
use crate::principal_middleware::{AuthStatus, RequestAuthContext};
|
||||
use crate::server;
|
||||
use crate::web_auth::SessionCookie;
|
||||
|
||||
fn test_cookie_key() -> Key {
|
||||
|
|
@ -1303,7 +1302,7 @@ client_id = "github-client-id"
|
|||
settings: fabro_types::ServerSettings,
|
||||
auth_mode: AuthMode,
|
||||
) -> (axum::Router, Arc<crate::server::AppState>) {
|
||||
let state = server::create_test_app_state_with_runtime_settings_and_session_key(
|
||||
let state = crate::test_support::test_app_state_with_runtime_settings_and_session_key(
|
||||
settings,
|
||||
RunLayer::default(),
|
||||
Some("cli-flow-test-key-material-0123456789"),
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ methods = ["dev-token"]
|
|||
}
|
||||
|
||||
fn test_state() -> Arc<server::AppState> {
|
||||
server::create_test_app_state_with_runtime_settings_and_session_key(
|
||||
crate::test_support::test_app_state_with_runtime_settings_and_session_key(
|
||||
test_server_settings(),
|
||||
RunLayer::default(),
|
||||
Some(SESSION_SECRET),
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::github_webhooks::WEBHOOK_ROUTE;
|
||||
use crate::server::{self, AppState};
|
||||
use crate::server::AppState;
|
||||
|
||||
macro_rules! assert_status {
|
||||
($response:expr, $expected:expr) => {
|
||||
|
|
@ -248,7 +248,7 @@ url = "{web_url}"
|
|||
}
|
||||
|
||||
fn state_with_web_url(web_url: &str) -> Arc<AppState> {
|
||||
server::create_app_state_with_options(
|
||||
crate::test_support::test_app_state_with_options(
|
||||
settings_with_web_url(web_url),
|
||||
RunLayer::default(),
|
||||
5,
|
||||
|
|
@ -256,7 +256,7 @@ url = "{web_url}"
|
|||
}
|
||||
|
||||
fn invalid_canonical_origin_state() -> Arc<AppState> {
|
||||
server::create_app_state_with_env_lookup(
|
||||
crate::test_support::test_app_state_with_env_lookup(
|
||||
settings_with_web_url("{{ env.FABRO_WEB_URL }}"),
|
||||
RunLayer::default(),
|
||||
5,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ mod server_secrets;
|
|||
mod spawn_env;
|
||||
mod startup;
|
||||
pub mod static_files;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test_support;
|
||||
pub mod web_auth;
|
||||
mod worker_token;
|
||||
|
|
|
|||
|
|
@ -508,14 +508,14 @@ mod tests {
|
|||
}
|
||||
|
||||
fn classify_token(token: Option<&str>) -> RequestAuthContext {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let request = request_with_bearer(token, auth_mode_for_state(state.as_ref()));
|
||||
classify_request(&request, state.as_ref())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_valid_user_jwt_as_user_principal() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let token = issue_user_token(state.as_ref(), Duration::minutes(10));
|
||||
let request = request_with_bearer(Some(&token), auth_mode_for_state(state.as_ref()));
|
||||
|
||||
|
|
@ -528,7 +528,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn classifies_expired_user_jwt_as_expired() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let token = issue_user_token(state.as_ref(), Duration::seconds(-60));
|
||||
let request = request_with_bearer(Some(&token), auth_mode_for_state(state.as_ref()));
|
||||
|
||||
|
|
@ -554,7 +554,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn routes_worker_kid_to_worker_verifier() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let run_id = RunId::new();
|
||||
let token = issue_worker_token(state.worker_token_keys(), &run_id).unwrap();
|
||||
let request = request_with_bearer(Some(&token), auth_mode_for_state(state.as_ref()));
|
||||
|
|
@ -567,7 +567,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn classifies_expired_worker_jwt_as_expired_not_invalid() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let token = issue_worker_claims(state.as_ref(), RunId::new(), 2, WORKER_TOKEN_SCOPE);
|
||||
let request = request_with_bearer(Some(&token), auth_mode_for_state(state.as_ref()));
|
||||
|
||||
|
|
@ -582,7 +582,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn classifies_invalid_worker_jwt_signature_as_invalid() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let token = issue_worker_claims_with_secret(
|
||||
b"other-principal-middleware-secret-0001",
|
||||
RunId::new(),
|
||||
|
|
@ -602,7 +602,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn classifies_wrong_scope_worker_jwt_as_invalid() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let token = issue_worker_claims(state.as_ref(), RunId::new(), u64::MAX / 2, "wrong:scope");
|
||||
let request = request_with_bearer(Some(&token), auth_mode_for_state(state.as_ref()));
|
||||
|
||||
|
|
|
|||
|
|
@ -1722,7 +1722,7 @@ app_id = "fixture-app-id"
|
|||
|
||||
#[tokio::test]
|
||||
async fn invalid_preflight_returns_diagnostics_without_runtime_checks() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let prepared = prepare_manifest(
|
||||
&manifest_run_defaults(Some(&default_settings_fixture())),
|
||||
&invalid_manifest(),
|
||||
|
|
@ -1746,7 +1746,7 @@ app_id = "fixture-app-id"
|
|||
|
||||
#[tokio::test]
|
||||
async fn preflight_allows_pull_request_enabled_without_github_credentials() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let mut manifest = minimal_manifest();
|
||||
manifest.configs.push(types::ManifestConfig {
|
||||
path: Some("/tmp/project/.fabro/project.toml".to_string()),
|
||||
|
|
@ -1790,7 +1790,7 @@ provider = "local"
|
|||
|
||||
#[tokio::test]
|
||||
async fn preflight_daytona_without_github_credentials_returns_report() {
|
||||
let state = crate::server::create_app_state();
|
||||
let state = crate::test_support::test_app_state();
|
||||
let mut manifest = minimal_manifest();
|
||||
manifest.configs.push(types::ManifestConfig {
|
||||
path: Some("/tmp/project/.fabro/project.toml".to_string()),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
#[cfg(test)]
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::extract::Request;
|
||||
#[cfg(test)]
|
||||
|
|
@ -9,23 +12,376 @@ use axum::http::{HeaderValue, header};
|
|||
use axum::middleware::Next;
|
||||
use axum::response::Response;
|
||||
use axum::{Router, middleware};
|
||||
use chrono::Duration;
|
||||
use chrono::Duration as ChronoDuration;
|
||||
use fabro_config::{RunLayer, RunSettingsBuilder, ServerSettingsBuilder, envfile};
|
||||
use fabro_interview::Interviewer;
|
||||
use fabro_static::EnvVars;
|
||||
use fabro_store::{ArtifactStore, Database};
|
||||
use fabro_types::settings::ServerAuthMethod;
|
||||
use fabro_types::{AuthMethod, IdpIdentity};
|
||||
use fabro_types::{AuthMethod, IdpIdentity, ServerSettings};
|
||||
use fabro_util::error::SharedError;
|
||||
use fabro_workflow::handler::HandlerRegistry;
|
||||
use object_store::memory::InMemory as MemoryObjectStore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::auth;
|
||||
use crate::ip_allowlist::IpAllowlistConfig;
|
||||
use crate::jwt_auth::{AuthMode, ConfiguredAuth};
|
||||
#[cfg(test)]
|
||||
use crate::principal_middleware::{AuthContextSlot, RequestAuthContext};
|
||||
use crate::server::{self, AppState, RouterOptions};
|
||||
use crate::server::{
|
||||
self, AppState, AppStateConfig, EnvLookup, ResolvedAppStateSettings, RouterOptions,
|
||||
build_app_state, process_env_var,
|
||||
};
|
||||
use crate::server_secrets::ServerSecrets;
|
||||
|
||||
pub const TEST_DEV_TOKEN: &str =
|
||||
"fabro_dev_abababababababababababababababababababababababababababababababab";
|
||||
pub const TEST_SESSION_SECRET: &str =
|
||||
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn default_test_server_settings() -> ServerSettings {
|
||||
ServerSettingsBuilder::from_toml(
|
||||
r#"
|
||||
_version = 1
|
||||
|
||||
[server.auth]
|
||||
methods = ["dev-token"]
|
||||
"#,
|
||||
)
|
||||
.expect("default test server settings should resolve")
|
||||
}
|
||||
|
||||
pub fn test_app_state() -> Arc<AppState> {
|
||||
test_app_state_with_options(default_test_server_settings(), RunLayer::default(), 5)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_registry_factory(
|
||||
registry_factory_override: impl Fn(Arc<dyn Interviewer>) -> HandlerRegistry + Send + Sync + 'static,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_settings_and_registry_factory(
|
||||
default_test_server_settings(),
|
||||
RunLayer::default(),
|
||||
registry_factory_override,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_settings_and_registry_factory(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
registry_factory_override: impl Fn(Arc<dyn Interviewer>) -> HandlerRegistry + Send + Sync + 'static,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_options_and_registry_factory(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
5,
|
||||
registry_factory_override,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_options_and_registry_factory(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
registry_factory_override: impl Fn(Arc<dyn Interviewer>) -> HandlerRegistry + Send + Sync + 'static,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_options_and_registry_factory(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
registry_factory_override,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_options(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_options(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn resolved_runtime_settings_for_tests(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
) -> ResolvedAppStateSettings {
|
||||
ResolvedAppStateSettings {
|
||||
manifest_run_settings: RunSettingsBuilder::from_run_layer(&manifest_run_defaults)
|
||||
.map_err(|err| SharedError::new(anyhow::Error::new(err))),
|
||||
manifest_run_defaults,
|
||||
server_settings,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_runtime_settings_and_registry_factory(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
registry_factory_override: impl Fn(Arc<dyn Interviewer>) -> HandlerRegistry + Send + Sync + 'static,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_options_and_registry_factory(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
5,
|
||||
registry_factory_override,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_runtime_settings_and_options_and_registry_factory(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
registry_factory_override: impl Fn(Arc<dyn Interviewer>) -> HandlerRegistry + Send + Sync + 'static,
|
||||
) -> Arc<AppState> {
|
||||
let (store, artifact_store) = test_store_bundle();
|
||||
let vault_path = test_secret_store_path();
|
||||
let server_env_path = vault_path.with_file_name("server.env");
|
||||
let env_lookup = default_env_lookup();
|
||||
let mut config = AppStateConfig {
|
||||
resolved_settings: resolved_runtime_settings_for_tests(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
),
|
||||
registry_factory_override: None,
|
||||
max_concurrent_runs,
|
||||
store,
|
||||
artifact_store,
|
||||
vault_path,
|
||||
server_secrets: load_test_server_secrets(server_env_path, HashMap::new()),
|
||||
env_lookup,
|
||||
github_api_base_url: None,
|
||||
http_client: Some(fabro_http::test_http_client().expect("test HTTP client should build")),
|
||||
};
|
||||
config.registry_factory_override = Some(Box::new(registry_factory_override));
|
||||
build_app_state(config).expect("test app state should build")
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_runtime_settings_and_options(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
process_env_var,
|
||||
&HashMap::new(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_runtime_settings_and_env_lookup(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
env_lookup: impl Fn(&str) -> Option<String> + Send + Sync + 'static,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
env_lookup,
|
||||
&HashMap::new(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
env_lookup: impl Fn(&str) -> Option<String> + Send + Sync + 'static,
|
||||
server_secret_env: &HashMap<String, String>,
|
||||
) -> Arc<AppState> {
|
||||
let (store, artifact_store) = test_store_bundle();
|
||||
let env_lookup: EnvLookup = Arc::new(env_lookup);
|
||||
let vault_path = test_secret_store_path();
|
||||
let server_env_path = vault_path.with_file_name("server.env");
|
||||
build_app_state(AppStateConfig {
|
||||
resolved_settings: resolved_runtime_settings_for_tests(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
),
|
||||
registry_factory_override: None,
|
||||
max_concurrent_runs,
|
||||
store,
|
||||
artifact_store,
|
||||
vault_path,
|
||||
server_secrets: load_test_server_secrets(server_env_path, server_secret_env.clone()),
|
||||
env_lookup,
|
||||
github_api_base_url: None,
|
||||
http_client: Some(fabro_http::test_http_client().expect("test HTTP client should build")),
|
||||
})
|
||||
.expect("test app state should build")
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_env_lookup(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
env_lookup: impl Fn(&str) -> Option<String> + Send + Sync + 'static,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_env_lookup(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
env_lookup,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_env_lookup_and_server_secret_env(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
env_lookup: impl Fn(&str) -> Option<String> + Send + Sync + 'static,
|
||||
server_secret_env: &HashMap<String, String>,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
env_lookup,
|
||||
server_secret_env,
|
||||
)
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "test helper writes a fixture server.env with sync std::fs::write"
|
||||
)]
|
||||
pub fn test_app_state_with_runtime_settings_and_session_key(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
session_secret: Option<&str>,
|
||||
) -> Arc<AppState> {
|
||||
let vault_path = test_secret_store_path();
|
||||
let server_env_path = vault_path
|
||||
.parent()
|
||||
.expect("test secrets path should have parent")
|
||||
.join("server.env");
|
||||
if let Some(session_secret) = session_secret {
|
||||
std::fs::write(
|
||||
&server_env_path,
|
||||
format!("SESSION_SECRET={session_secret}\n"),
|
||||
)
|
||||
.expect("test server env should be writable");
|
||||
}
|
||||
let (store, artifact_store) = test_store_bundle();
|
||||
let env_lookup = default_env_lookup();
|
||||
build_app_state(AppStateConfig {
|
||||
resolved_settings: resolved_runtime_settings_for_tests(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
),
|
||||
registry_factory_override: None,
|
||||
max_concurrent_runs: 5,
|
||||
store,
|
||||
artifact_store,
|
||||
vault_path,
|
||||
server_secrets: load_test_server_secrets(server_env_path, HashMap::new()),
|
||||
env_lookup,
|
||||
github_api_base_url: None,
|
||||
http_client: Some(fabro_http::test_http_client().expect("test HTTP client should build")),
|
||||
})
|
||||
.expect("test app state should build")
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_session_key(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
session_secret: Option<&str>,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_runtime_settings_and_session_key(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
session_secret,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_store(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
store: Arc<Database>,
|
||||
artifact_store: ArtifactStore,
|
||||
) -> Arc<AppState> {
|
||||
test_app_state_with_store_and_runtime_settings(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
store,
|
||||
artifact_store,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_store_bundle() -> (Arc<Database>, ArtifactStore) {
|
||||
let object_store: Arc<dyn object_store::ObjectStore> = Arc::new(MemoryObjectStore::new());
|
||||
let store = Arc::new(fabro_store::Database::new(
|
||||
Arc::clone(&object_store),
|
||||
"",
|
||||
Duration::from_millis(1),
|
||||
None,
|
||||
));
|
||||
let artifact_store = ArtifactStore::new(object_store, "artifacts");
|
||||
(store, artifact_store)
|
||||
}
|
||||
|
||||
pub fn test_app_state_with_store_and_runtime_settings(
|
||||
server_settings: ServerSettings,
|
||||
manifest_run_defaults: RunLayer,
|
||||
max_concurrent_runs: usize,
|
||||
store: Arc<Database>,
|
||||
artifact_store: ArtifactStore,
|
||||
) -> Arc<AppState> {
|
||||
let vault_path = test_secret_store_path();
|
||||
let server_env_path = vault_path.with_file_name("server.env");
|
||||
build_app_state(AppStateConfig {
|
||||
resolved_settings: resolved_runtime_settings_for_tests(
|
||||
server_settings,
|
||||
manifest_run_defaults,
|
||||
),
|
||||
registry_factory_override: None,
|
||||
max_concurrent_runs,
|
||||
store,
|
||||
artifact_store,
|
||||
vault_path,
|
||||
server_secrets: load_test_server_secrets(server_env_path, HashMap::new()),
|
||||
env_lookup: default_env_lookup(),
|
||||
github_api_base_url: None,
|
||||
http_client: Some(fabro_http::test_http_client().expect("test HTTP client should build")),
|
||||
})
|
||||
.expect("test app state should build")
|
||||
}
|
||||
|
||||
pub(crate) fn default_env_lookup() -> EnvLookup {
|
||||
Arc::new(process_env_var)
|
||||
}
|
||||
|
||||
pub(crate) fn load_test_server_secrets(
|
||||
path: PathBuf,
|
||||
env: HashMap<String, String>,
|
||||
) -> ServerSecrets {
|
||||
let mut env = env;
|
||||
let file_has_session_secret = envfile::read_env_file(&path)
|
||||
.ok()
|
||||
.is_some_and(|entries| entries.contains_key(EnvVars::SESSION_SECRET));
|
||||
if !env.contains_key(EnvVars::SESSION_SECRET) && !file_has_session_secret {
|
||||
env.insert(
|
||||
EnvVars::SESSION_SECRET.to_string(),
|
||||
"server-test-session-key-0123456789".to_string(),
|
||||
);
|
||||
}
|
||||
ServerSecrets::load(path, env).expect("test server secrets should load")
|
||||
}
|
||||
|
||||
pub fn test_secret_store_path() -> PathBuf {
|
||||
let dir = std::env::temp_dir().join(format!("fabro-test-{}", Ulid::new()));
|
||||
std::fs::create_dir_all(&dir).expect("test temp dir should be creatable");
|
||||
dir.join("secrets.json")
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn test_auth_mode() -> AuthMode {
|
||||
AuthMode::Enabled(ConfiguredAuth {
|
||||
|
|
@ -39,12 +395,10 @@ pub fn test_auth_mode() -> AuthMode {
|
|||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn build_test_router(state: Arc<AppState>) -> Router {
|
||||
with_test_user(server::build_router(state, test_auth_mode()))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn build_test_router_with_options(
|
||||
state: Arc<AppState>,
|
||||
ip_allowlist_config: Arc<IpAllowlistConfig>,
|
||||
|
|
@ -58,7 +412,6 @@ pub fn build_test_router_with_options(
|
|||
))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn with_test_user(router: Router) -> Router {
|
||||
router.layer(middleware::from_fn(inject_test_user_bearer))
|
||||
}
|
||||
|
|
@ -92,7 +445,7 @@ fn issue_test_user_token() -> String {
|
|||
user_url: String::new(),
|
||||
auth_method: AuthMethod::DevToken,
|
||||
},
|
||||
Duration::days(3650),
|
||||
ChronoDuration::days(3650),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -972,7 +972,7 @@ client_id = "github-client-id"
|
|||
settings: fabro_types::ServerSettings,
|
||||
auth_mode: AuthMode,
|
||||
) -> axum::Router {
|
||||
let state = server::create_test_app_state_with_runtime_settings_and_session_key(
|
||||
let state = crate::test_support::test_app_state_with_runtime_settings_and_session_key(
|
||||
settings,
|
||||
RunLayer::default(),
|
||||
Some("web-auth-test-key-material-0123456789"),
|
||||
|
|
@ -1002,7 +1002,7 @@ client_id = "github-client-id"
|
|||
auth_mode: AuthMode,
|
||||
) -> (axum::Router, Arc<Mutex<Vec<RequestAuthContext>>>) {
|
||||
let captured = Arc::new(Mutex::new(Vec::new()));
|
||||
let state = server::create_test_app_state_with_runtime_settings_and_session_key(
|
||||
let state = crate::test_support::test_app_state_with_runtime_settings_and_session_key(
|
||||
settings,
|
||||
RunLayer::default(),
|
||||
Some("web-auth-test-key-material-0123456789"),
|
||||
|
|
@ -1242,7 +1242,7 @@ client_id = "github-client-id"
|
|||
|
||||
#[tokio::test]
|
||||
async fn auth_config_returns_real_methods_when_demo_cookie_set() {
|
||||
let state = server::create_test_app_state_with_runtime_settings_and_session_key(
|
||||
let state = crate::test_support::test_app_state_with_runtime_settings_and_session_key(
|
||||
github_settings("https://fabro.example"),
|
||||
RunLayer::default(),
|
||||
Some("web-auth-test-key-material-0123456789"),
|
||||
|
|
@ -1335,7 +1335,7 @@ client_id = "github-client-id"
|
|||
|
||||
#[tokio::test]
|
||||
async fn login_github_uses_injected_github_endpoints() {
|
||||
let state = server::create_test_app_state_with_runtime_settings_and_session_key(
|
||||
let state = crate::test_support::test_app_state_with_runtime_settings_and_session_key(
|
||||
github_settings("https://fabro.example"),
|
||||
RunLayer::default(),
|
||||
Some("web-auth-test-key-material-0123456789"),
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@ use axum::http::{Request, StatusCode, header};
|
|||
use base64::Engine;
|
||||
use fabro_server::ip_allowlist::IpAllowlistConfig;
|
||||
use fabro_server::jwt_auth::resolve_auth_mode_with_lookup;
|
||||
use fabro_server::server::{
|
||||
RouterOptions, build_router_with_options, create_app_state_with_store_and_runtime_settings,
|
||||
};
|
||||
use fabro_server::server::{RouterOptions, build_router_with_options};
|
||||
use fabro_server::test_support::test_app_state_with_store_and_runtime_settings;
|
||||
use fabro_store::{ArtifactStore, AuthCode, Database, RefreshToken};
|
||||
use object_store::memory::InMemory;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
|
@ -35,7 +34,7 @@ fn test_app(source: &str) -> (axum::Router, Arc<Database>) {
|
|||
})
|
||||
.expect("auth mode should resolve");
|
||||
let app = build_router_with_options(
|
||||
create_app_state_with_store_and_runtime_settings(
|
||||
test_app_state_with_store_and_runtime_settings(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ use axum::http::{Method, Request, StatusCode};
|
|||
use fabro_config::ServerSettingsBuilder;
|
||||
use fabro_server::ip_allowlist::{IpAllowlist, IpAllowlistConfig};
|
||||
use fabro_server::jwt_auth::{AuthMode, resolve_auth_mode_with_lookup};
|
||||
use fabro_server::server::{
|
||||
RouterOptions, build_router, create_app_state,
|
||||
create_app_state_with_runtime_settings_and_options,
|
||||
use fabro_server::server::{RouterOptions, build_router};
|
||||
use fabro_server::test_support::{
|
||||
TEST_DEV_TOKEN, TEST_SESSION_SECRET, test_app_state,
|
||||
test_app_state_with_runtime_settings_and_options,
|
||||
};
|
||||
use fabro_server::test_support::{TEST_DEV_TOKEN, TEST_SESSION_SECRET};
|
||||
use tower::ServiceExt;
|
||||
|
||||
use crate::helpers::{
|
||||
|
|
@ -44,7 +44,7 @@ fn spa_fixture_root() -> PathBuf {
|
|||
|
||||
#[tokio::test]
|
||||
async fn old_unversioned_routes_return_404() {
|
||||
let app = fabro_server::test_support::build_test_router(create_app_state());
|
||||
let app = fabro_server::test_support::build_test_router(test_app_state());
|
||||
|
||||
let cases = [(Method::POST, "/completions")];
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ async fn old_unversioned_routes_return_404() {
|
|||
#[tokio::test]
|
||||
async fn root_and_health_stay_at_root() {
|
||||
let app = fabro_server::test_support::build_test_router_with_options(
|
||||
create_app_state(),
|
||||
test_app_state(),
|
||||
Arc::new(IpAllowlistConfig::default()),
|
||||
RouterOptions {
|
||||
static_asset_root: Some(spa_fixture_root()),
|
||||
|
|
@ -95,7 +95,7 @@ async fn root_and_health_stay_at_root() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn install_routes_are_absent_in_normal_mode() {
|
||||
let app = fabro_server::test_support::build_test_router(create_app_state());
|
||||
let app = fabro_server::test_support::build_test_router(test_app_state());
|
||||
|
||||
let response = app
|
||||
.oneshot(
|
||||
|
|
@ -113,7 +113,7 @@ async fn install_routes_are_absent_in_normal_mode() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn moved_routes_not_at_root_of_api_prefix() {
|
||||
let app = fabro_server::test_support::build_test_router(create_app_state());
|
||||
let app = fabro_server::test_support::build_test_router(test_app_state());
|
||||
|
||||
for path in ["/api/v1/health", "/api/v1/"] {
|
||||
let req = Request::builder()
|
||||
|
|
@ -128,7 +128,7 @@ async fn moved_routes_not_at_root_of_api_prefix() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn source_maps_are_not_served() {
|
||||
let app = fabro_server::test_support::build_test_router(create_app_state());
|
||||
let app = fabro_server::test_support::build_test_router(test_app_state());
|
||||
|
||||
let request = Request::builder()
|
||||
.method("GET")
|
||||
|
|
@ -149,7 +149,7 @@ async fn source_maps_are_not_served() {
|
|||
async fn web_enabled_serves_web_only_routes() {
|
||||
let auth_mode = dev_token_enabled_auth_mode();
|
||||
let app = fabro_server::server::build_router_with_options(
|
||||
create_app_state(),
|
||||
test_app_state(),
|
||||
&auth_mode,
|
||||
Arc::new(IpAllowlistConfig::default()),
|
||||
RouterOptions {
|
||||
|
|
@ -260,7 +260,7 @@ async fn web_enabled_serves_web_only_routes() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn toggle_demo_rejects_unauthenticated_requests() {
|
||||
let app = build_router(create_app_state(), dev_token_enabled_auth_mode());
|
||||
let app = build_router(test_app_state(), dev_token_enabled_auth_mode());
|
||||
|
||||
let response = app
|
||||
.oneshot(
|
||||
|
|
@ -283,7 +283,7 @@ async fn toggle_demo_rejects_unauthenticated_requests() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn toggle_demo_allows_authenticated_requests() {
|
||||
let app = build_router(create_app_state(), dev_token_enabled_auth_mode());
|
||||
let app = build_router(test_app_state(), dev_token_enabled_auth_mode());
|
||||
|
||||
let response = checked_response(
|
||||
app.oneshot(
|
||||
|
|
@ -314,7 +314,7 @@ async fn toggle_demo_allows_authenticated_requests() {
|
|||
#[tokio::test]
|
||||
async fn security_headers_are_applied_to_all_responses() {
|
||||
let app = fabro_server::test_support::build_test_router_with_options(
|
||||
create_app_state(),
|
||||
test_app_state(),
|
||||
Arc::new(IpAllowlistConfig::default()),
|
||||
RouterOptions {
|
||||
static_asset_root: Some(spa_fixture_root()),
|
||||
|
|
@ -448,7 +448,7 @@ enabled = false
|
|||
",
|
||||
);
|
||||
let app = fabro_server::test_support::build_test_router_with_options(
|
||||
create_app_state_with_runtime_settings_and_options(
|
||||
test_app_state_with_runtime_settings_and_options(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
@ -512,7 +512,7 @@ enabled = false
|
|||
",
|
||||
);
|
||||
let app = fabro_server::test_support::build_test_router_with_options(
|
||||
create_app_state_with_runtime_settings_and_options(
|
||||
test_app_state_with_runtime_settings_and_options(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
@ -539,7 +539,7 @@ enabled = false
|
|||
#[tokio::test]
|
||||
async fn allowlist_blocks_non_allowlisted_api_requests() {
|
||||
let app = fabro_server::test_support::build_test_router_with_options(
|
||||
create_app_state(),
|
||||
test_app_state(),
|
||||
Arc::new(IpAllowlistConfig {
|
||||
allowlist: IpAllowlist::new(vec!["10.0.0.0/8".parse().unwrap()]),
|
||||
trusted_proxy_count: 0,
|
||||
|
|
@ -561,7 +561,7 @@ async fn allowlist_blocks_non_allowlisted_api_requests() {
|
|||
#[tokio::test]
|
||||
async fn allowlist_exempts_health_checks() {
|
||||
let app = fabro_server::test_support::build_test_router_with_options(
|
||||
create_app_state(),
|
||||
test_app_state(),
|
||||
Arc::new(IpAllowlistConfig {
|
||||
allowlist: IpAllowlist::new(vec!["10.0.0.0/8".parse().unwrap()]),
|
||||
trusted_proxy_count: 0,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use std::time::Duration;
|
|||
|
||||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_server::server::create_app_state_with_store;
|
||||
use fabro_server::test_support::test_app_state_with_store;
|
||||
use fabro_store::{ArtifactStore, Database};
|
||||
use fabro_types::RunId;
|
||||
use fabro_workflow::event as workflow_event;
|
||||
|
|
@ -224,7 +224,7 @@ async fn submitted_run_without_sandbox_returns_empty_envelope() {
|
|||
async fn degraded_run_returns_file_diff_shape_without_meta_patch() {
|
||||
let settings = test_settings();
|
||||
let (store, artifact_store) = store_bundle();
|
||||
let state = create_app_state_with_store(
|
||||
let state = test_app_state_with_store(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_server::server::create_app_state_with_runtime_settings_and_options;
|
||||
use fabro_server::test_support::test_app_state_with_runtime_settings_and_options;
|
||||
use tower::ServiceExt;
|
||||
|
||||
use crate::helpers::{response_json, settings_from_toml};
|
||||
|
|
@ -32,7 +32,7 @@ client_id = "Iv1.abcdef"
|
|||
"#,
|
||||
);
|
||||
let app = fabro_server::test_support::build_test_router(
|
||||
create_app_state_with_runtime_settings_and_options(
|
||||
test_app_state_with_runtime_settings_and_options(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ use fabro_config::{RuntimeDirectory, ServerSettingsBuilder};
|
|||
use fabro_server::ip_allowlist::{IpAllowlist, IpAllowlistConfig};
|
||||
use fabro_server::jwt_auth::{AuthMode, resolve_auth_mode_with_lookup};
|
||||
use fabro_server::serve::{ServeArgs, serve_command};
|
||||
use fabro_server::server::{RouterOptions, build_router_with_options, create_app_state};
|
||||
use fabro_server::test_support::{TEST_DEV_TOKEN, TEST_SESSION_SECRET};
|
||||
use fabro_server::server::{RouterOptions, build_router_with_options};
|
||||
use fabro_server::test_support::{TEST_DEV_TOKEN, TEST_SESSION_SECRET, test_app_state};
|
||||
use fabro_util::terminal::Styles;
|
||||
use tempfile::TempDir;
|
||||
use tokio::net::TcpListener;
|
||||
|
|
@ -32,7 +32,7 @@ async fn start_tcp_server(auth_mode: AuthMode, ip_allowlist: Arc<IpAllowlistConf
|
|||
.local_addr()
|
||||
.expect("test TCP listener should have a local address");
|
||||
|
||||
let state = create_app_state();
|
||||
let state = test_app_state();
|
||||
let router =
|
||||
build_router_with_options(state, &auth_mode, ip_allowlist, RouterOptions::default());
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ use std::time::Duration;
|
|||
use axum::body::{Body, to_bytes};
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_config::{LocalSandboxLayer, RunLayer, RunSandboxLayer, ServerSettingsBuilder};
|
||||
use fabro_server::server::{
|
||||
AppState, create_app_state, create_app_state_with_runtime_settings_and_env_lookup,
|
||||
create_app_state_with_runtime_settings_and_options_and_registry_factory, spawn_scheduler,
|
||||
use fabro_server::server::{AppState, spawn_scheduler};
|
||||
use fabro_server::test_support::{
|
||||
build_test_router, test_app_state as server_test_app_state,
|
||||
test_app_state_with_runtime_settings_and_env_lookup,
|
||||
test_app_state_with_runtime_settings_and_options_and_registry_factory,
|
||||
};
|
||||
use fabro_server::test_support::build_test_router;
|
||||
use fabro_test::{
|
||||
assert_axum_status, assert_reqwest_status, expect_axum_json, expect_axum_status,
|
||||
expect_axum_status_in, expect_axum_text,
|
||||
|
|
@ -76,14 +77,14 @@ pub(crate) fn settings_from_toml(source: &str) -> TestAppSettings {
|
|||
}
|
||||
|
||||
pub(crate) fn test_app_state() -> Arc<AppState> {
|
||||
create_app_state()
|
||||
server_test_app_state()
|
||||
}
|
||||
|
||||
pub(crate) fn test_app_state_with_options(
|
||||
settings: TestAppSettings,
|
||||
max_concurrent_runs: usize,
|
||||
) -> Arc<AppState> {
|
||||
create_app_state_with_runtime_settings_and_options_and_registry_factory(
|
||||
test_app_state_with_runtime_settings_and_options_and_registry_factory(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
max_concurrent_runs,
|
||||
|
|
@ -114,7 +115,7 @@ pub(crate) fn test_app_with_scheduler(state: Arc<AppState>) -> axum::Router {
|
|||
|
||||
pub(crate) fn test_app_with_no_providers() -> axum::Router {
|
||||
let settings = test_settings();
|
||||
let state = create_app_state_with_runtime_settings_and_env_lookup(
|
||||
let state = test_app_state_with_runtime_settings_and_env_lookup(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
@ -126,7 +127,7 @@ pub(crate) fn test_app_with_no_providers() -> axum::Router {
|
|||
pub(crate) fn test_app_with_mock_anthropic(mock_base_url: &str) -> axum::Router {
|
||||
let base_url = mock_base_url.to_string();
|
||||
let settings = test_settings();
|
||||
let state = create_app_state_with_runtime_settings_and_env_lookup(
|
||||
let state = test_app_state_with_runtime_settings_and_env_lookup(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
use axum::body::Body;
|
||||
use axum::http::{Method, Request, StatusCode};
|
||||
use fabro_server::install::{InstallAppState, build_install_router};
|
||||
use fabro_server::server::create_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env;
|
||||
use fabro_server::test_support::test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env;
|
||||
use serde_yaml::Value;
|
||||
use tower::ServiceExt;
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ async fn github_webhook_spec_route_is_routable_when_webhook_secret_is_present()
|
|||
let secret = "test-webhook-secret".to_string();
|
||||
let settings = test_settings();
|
||||
let app = fabro_server::test_support::build_test_router(
|
||||
create_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
test_app_state_with_runtime_settings_and_env_lookup_and_server_secret_env(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
5,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@ use std::sync::Arc;
|
|||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_interview::Interviewer;
|
||||
use fabro_server::server::{
|
||||
create_app_state_with_runtime_settings_and_registry_factory, spawn_scheduler,
|
||||
};
|
||||
use fabro_server::server::spawn_scheduler;
|
||||
use fabro_server::test_support::test_app_state_with_runtime_settings_and_registry_factory;
|
||||
use fabro_workflow::handler::HandlerRegistry;
|
||||
use fabro_workflow::handler::agent::AgentHandler;
|
||||
use fabro_workflow::handler::exit::ExitHandler;
|
||||
|
|
@ -119,7 +118,7 @@ const GATE_DOT: &str = r#"digraph GateTest {
|
|||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn full_http_lifecycle_approve_and_complete() {
|
||||
let settings = test_settings();
|
||||
let state = create_app_state_with_runtime_settings_and_registry_factory(
|
||||
let state = test_app_state_with_runtime_settings_and_registry_factory(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
gate_registry,
|
||||
|
|
@ -207,7 +206,7 @@ async fn full_http_lifecycle_approve_and_complete() {
|
|||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn full_http_lifecycle_cancel() {
|
||||
let settings = test_settings();
|
||||
let state = create_app_state_with_runtime_settings_and_registry_factory(
|
||||
let state = test_app_state_with_runtime_settings_and_registry_factory(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
gate_registry,
|
||||
|
|
@ -278,7 +277,7 @@ async fn full_http_lifecycle_cancel() {
|
|||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn cancel_at_human_gate_persists_cancelled_terminal_event() {
|
||||
let settings = test_settings();
|
||||
let state = create_app_state_with_runtime_settings_and_registry_factory(
|
||||
let state = test_app_state_with_runtime_settings_and_registry_factory(
|
||||
settings.server_settings,
|
||||
settings.manifest_run_defaults,
|
||||
gate_registry,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue