feat: wire relay API with dependency injection

- split settings module into per-struct files
- add DatabaseSettings with default in-memory SQLite path
- implement RelayApi struct with GET /relays and POST
  /relays/{id}/toggle
- wire create_relay_controller and create_label_repository into
  Application::build() with mock/real selection via cfg!(test) || CI
- register RelayApi in OpenApiService alongside existing APIs
This commit is contained in:
2026-03-04 12:47:21 +01:00
parent fd00d1925b
commit 2eebc52f17
30 changed files with 1170 additions and 670 deletions

View File

@@ -13,7 +13,7 @@ use poem::test::TestClient;
use sta::{settings::Settings, startup::Application};
/// Helper function to create a test app with custom CORS settings.
fn get_test_app_with_cors(
async fn get_test_app_with_cors(
allowed_origins: Vec<String>,
allow_credentials: bool,
max_age_secs: i32,
@@ -32,6 +32,8 @@ fn get_test_app_with_cors(
settings.cors.max_age_secs = max_age_secs;
Application::build(settings, Some(listener))
.await
.expect("Failed to build application")
.make_app()
.into()
}
@@ -42,7 +44,7 @@ fn get_test_app_with_cors(
#[tokio::test]
async fn preflight_request_returns_cors_headers() {
// GIVEN: An app with CORS configured for specific origin
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600);
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600).await;
let client = TestClient::new(app);
// WHEN: A preflight OPTIONS request is sent with Origin header
@@ -82,7 +84,7 @@ async fn preflight_request_returns_cors_headers() {
#[tokio::test]
async fn get_request_with_origin_returns_allow_origin_header() {
// GIVEN: An app with CORS configured for specific origin
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600);
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600).await;
let client = TestClient::new(app);
// WHEN: A GET request is sent with Origin header
@@ -119,7 +121,7 @@ async fn preflight_response_includes_max_age_from_config() {
vec!["http://localhost:5173".to_string()],
false,
custom_max_age,
);
).await;
let client = TestClient::new(app);
// WHEN: A preflight OPTIONS request is sent
@@ -153,7 +155,7 @@ async fn response_includes_allow_credentials_when_configured() {
vec!["http://localhost:5173".to_string()],
true, // allow_credentials
3600,
);
).await;
let client = TestClient::new(app);
// WHEN: A preflight OPTIONS request is sent
@@ -187,7 +189,7 @@ async fn response_does_not_include_credentials_when_disabled() {
vec!["http://localhost:5173".to_string()],
false, // allow_credentials
3600,
);
).await;
let client = TestClient::new(app);
// WHEN: A preflight OPTIONS request is sent
@@ -217,7 +219,7 @@ async fn response_does_not_include_credentials_when_disabled() {
#[tokio::test]
async fn preflight_response_includes_correct_allowed_methods() {
// GIVEN: An app with CORS configured
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600);
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600).await;
let client = TestClient::new(app);
// WHEN: A preflight OPTIONS request is sent
@@ -260,7 +262,7 @@ async fn wildcard_origin_works_with_credentials_disabled() {
vec!["*".to_string()],
false, // credentials MUST be false with wildcard
3600,
);
).await;
let client = TestClient::new(app);
// WHEN: A preflight OPTIONS request is sent with any origin
@@ -299,7 +301,7 @@ async fn multiple_origins_are_supported() {
],
false,
3600,
);
).await;
let client = TestClient::new(app);
// WHEN: A request is sent with the first origin
@@ -341,7 +343,7 @@ async fn multiple_origins_are_supported() {
#[tokio::test]
async fn unauthorized_origin_is_rejected() {
// GIVEN: An app with CORS configured for specific origins only
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600);
let app = get_test_app_with_cors(vec!["http://localhost:5173".to_string()], false, 3600).await;
let client = TestClient::new(app);
// WHEN: A request is sent with an unauthorized origin