mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
test: remove infrastructure-dependent integration suites (#1573)
This commit is contained in:
@@ -4,22 +4,11 @@
|
||||
mod parity_support;
|
||||
|
||||
use parity_support::{
|
||||
PARITY_RUN_ENV, PROTECTED_ROUTES_ENV, PUBLIC_ROUTES_ENV, TEST_ACCESS_TOKEN, TEST_ADMIN_SECRET,
|
||||
TEST_ADMIN_USER_ID, api_fixtures, capture, env_flag, html_normalizer, reference_worktree,
|
||||
route_list_from_env, servers,
|
||||
TEST_ACCESS_TOKEN, TEST_ADMIN_SECRET, TEST_ADMIN_USER_ID, api_fixtures, capture,
|
||||
html_normalizer, rust_server,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
|
||||
const DEFAULT_PUBLIC_ROUTES: &[&str] = &["/_health", "/robots.txt", "/static/app.css", "/login"];
|
||||
const DEFAULT_PROTECTED_ROUTES: &[&str] = &[
|
||||
"/dashboard",
|
||||
"/users?q=Parity",
|
||||
"/guilds?q=Parity",
|
||||
"/guilds/1600000000000000001",
|
||||
"/reports",
|
||||
"/reports/1700000000000000001",
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn html_normalizer_canonicalizes_attribute_order_and_csrf_values() {
|
||||
let left = r#"<form><input value="aaaaaaaa" name="_csrf" type="hidden"><svg><line x1="1" x2="2"></line></svg><a class="b" href="/static/app.css?v=123" id="x">Open</a></form>"#;
|
||||
@@ -64,7 +53,7 @@ async fn rust_admin_fixture_routes_cover_default_protected_routes() -> Result<()
|
||||
let api_server = api_fixtures::ApiFixtureServer::start_default()
|
||||
.await
|
||||
.map_err(test_error)?;
|
||||
let rust_admin = servers::start_rust_admin(api_server.base_url())
|
||||
let rust_admin = rust_server::start(api_server.base_url())
|
||||
.await
|
||||
.map_err(test_error)?;
|
||||
let client = capture::capture_client().map_err(test_error)?;
|
||||
@@ -115,68 +104,6 @@ async fn rust_admin_fixture_routes_cover_default_protected_routes() -> Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore = "set FLUXER_ADMIN_PARITY_RUN=1 to create/use the TS worktree and run dual-server parity"]
|
||||
async fn dual_server_static_public_and_protected_routes() -> Result<(), Box<dyn Error>> {
|
||||
if !env_flag(PARITY_RUN_ENV) {
|
||||
eprintln!("skipping dual-server parity; set {PARITY_RUN_ENV}=1 to run it");
|
||||
return Ok(());
|
||||
}
|
||||
let repo_root = repo_root()?;
|
||||
let api_server = api_fixtures::ApiFixtureServer::start_default()
|
||||
.await
|
||||
.map_err(test_error)?;
|
||||
let worktree = reference_worktree::ensure_reference_worktree(&repo_root).map_err(test_error)?;
|
||||
reference_worktree::prepare_reference_package(&worktree).map_err(test_error)?;
|
||||
let ts_port = servers::reserve_local_port().map_err(test_error)?;
|
||||
let ts_admin = servers::start_ts_admin(&worktree, ts_port, api_server.base_url())
|
||||
.await
|
||||
.map_err(test_error)?;
|
||||
let rust_admin = servers::start_rust_admin(api_server.base_url())
|
||||
.await
|
||||
.map_err(test_error)?;
|
||||
let client = capture::capture_client().map_err(test_error)?;
|
||||
let public_routes = route_list_from_env(PUBLIC_ROUTES_ENV, DEFAULT_PUBLIC_ROUTES);
|
||||
for route in public_routes {
|
||||
capture::compare_route(
|
||||
&client,
|
||||
&route,
|
||||
ts_admin.base_url(),
|
||||
rust_admin.base_url(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(test_error)?;
|
||||
}
|
||||
let session = fluxer_admin::session::create_session(
|
||||
TEST_ADMIN_USER_ID,
|
||||
TEST_ACCESS_TOKEN,
|
||||
TEST_ADMIN_SECRET,
|
||||
);
|
||||
let session_cookie = format!("{}={session}", fluxer_admin::session::SESSION_COOKIE_NAME);
|
||||
let protected_routes = route_list_from_env(PROTECTED_ROUTES_ENV, DEFAULT_PROTECTED_ROUTES);
|
||||
for route in protected_routes {
|
||||
capture::compare_route(
|
||||
&client,
|
||||
&route,
|
||||
ts_admin.base_url(),
|
||||
rust_admin.base_url(),
|
||||
Some(&session_cookie),
|
||||
)
|
||||
.await
|
||||
.map_err(test_error)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn repo_root() -> Result<std::path::PathBuf, Box<dyn Error>> {
|
||||
let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
manifest_dir
|
||||
.parent()
|
||||
.map(std::path::Path::to_path_buf)
|
||||
.ok_or_else(|| test_error("fluxer_admin must have a repository parent".to_owned()))
|
||||
}
|
||||
|
||||
fn test_error(message: String) -> Box<dyn Error> {
|
||||
Box::new(io::Error::other(message))
|
||||
}
|
||||
|
||||
@@ -18,24 +18,6 @@ pub fn capture_client() -> Result<Client, String> {
|
||||
.map_err(|error| format!("failed to build capture client: {error}"))
|
||||
}
|
||||
|
||||
pub async fn compare_route(
|
||||
client: &Client,
|
||||
route: &str,
|
||||
ts_base_url: &str,
|
||||
rust_base_url: &str,
|
||||
cookie: Option<&str>,
|
||||
) -> Result<(), String> {
|
||||
let ts = fetch_route(client, ts_base_url, route, cookie).await?;
|
||||
let rust = fetch_route(client, rust_base_url, route, cookie).await?;
|
||||
if ts == rust {
|
||||
return Ok(());
|
||||
}
|
||||
Err(format!(
|
||||
"parity mismatch for {route}\nTS: {ts:#?}\nRust: {rust:#?}\nfirst body diff: {}",
|
||||
first_body_diff(&ts.body, &rust.body)
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn fetch_route(
|
||||
client: &Client,
|
||||
base_url: &str,
|
||||
@@ -73,25 +55,3 @@ pub async fn fetch_route(
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
fn first_body_diff(left: &str, right: &str) -> String {
|
||||
let left_chars = left.chars().collect::<Vec<_>>();
|
||||
let right_chars = right.chars().collect::<Vec<_>>();
|
||||
let max_len = left_chars.len().max(right_chars.len());
|
||||
for index in 0..max_len {
|
||||
if left_chars.get(index) != right_chars.get(index) {
|
||||
let left_preview = preview_from(&left_chars, index);
|
||||
let right_preview = preview_from(&right_chars, index);
|
||||
return format!("at char {index}: left `{left_preview}`, right `{right_preview}`");
|
||||
}
|
||||
}
|
||||
"bodies differ but no character diff was found".to_owned()
|
||||
}
|
||||
|
||||
fn preview_from(chars: &[char], start: usize) -> String {
|
||||
chars
|
||||
.iter()
|
||||
.skip(start.saturating_sub(20))
|
||||
.take(80)
|
||||
.collect::<String>()
|
||||
}
|
||||
|
||||
@@ -3,47 +3,8 @@
|
||||
pub mod api_fixtures;
|
||||
pub mod capture;
|
||||
pub mod html_normalizer;
|
||||
pub mod reference_worktree;
|
||||
pub mod servers;
|
||||
pub mod rust_server;
|
||||
|
||||
use std::env;
|
||||
|
||||
pub const TS_REFERENCE_COMMIT: &str = "4748f2f1e6589c325fca6391d6df3e3c3f6a0345^";
|
||||
pub const PARITY_RUN_ENV: &str = "FLUXER_ADMIN_PARITY_RUN";
|
||||
pub const PUBLIC_ROUTES_ENV: &str = "FLUXER_ADMIN_PARITY_PUBLIC_ROUTES";
|
||||
pub const PROTECTED_ROUTES_ENV: &str = "FLUXER_ADMIN_PARITY_PROTECTED_ROUTES";
|
||||
pub const TS_WORKTREE_ENV: &str = "FLUXER_ADMIN_PARITY_TS_WORKTREE";
|
||||
pub const TS_WORKTREE_ROOT_ENV: &str = "FLUXER_ADMIN_PARITY_WORKTREE_ROOT";
|
||||
pub const SKIP_TS_PREPARE_ENV: &str = "FLUXER_ADMIN_PARITY_SKIP_TS_PREPARE";
|
||||
pub const TEST_ADMIN_SECRET: &str = "test-admin-secret";
|
||||
pub const TEST_ADMIN_USER_ID: &str = "1130650140672000000";
|
||||
pub const TEST_ACCESS_TOKEN: &str = "parity-access-token";
|
||||
|
||||
pub fn env_flag(name: &str) -> bool {
|
||||
env::var(name)
|
||||
.map(|value| {
|
||||
matches!(
|
||||
value.trim().to_ascii_lowercase().as_str(),
|
||||
"1" | "true" | "yes" | "on"
|
||||
)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn route_list_from_env(name: &str, default: &[&str]) -> Vec<String> {
|
||||
match env::var(name) {
|
||||
Ok(value) => value
|
||||
.split(',')
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(|value| {
|
||||
if value.starts_with('/') {
|
||||
value.to_owned()
|
||||
} else {
|
||||
format!("/{value}")
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
Err(_) => default.iter().map(|route| (*route).to_owned()).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use super::{
|
||||
SKIP_TS_PREPARE_ENV, TS_REFERENCE_COMMIT, TS_WORKTREE_ENV, TS_WORKTREE_ROOT_ENV, env_flag,
|
||||
};
|
||||
use std::{
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
pub fn ensure_reference_worktree(repo_root: &Path) -> Result<PathBuf, String> {
|
||||
let target_commit = git_stdout(repo_root, &["rev-parse", TS_REFERENCE_COMMIT])?;
|
||||
if let Ok(path) = env::var(TS_WORKTREE_ENV) {
|
||||
let path = PathBuf::from(path);
|
||||
validate_worktree(&path, &target_commit)?;
|
||||
return Ok(path);
|
||||
}
|
||||
let root = env::var(TS_WORKTREE_ROOT_ENV)
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| repo_root.join("target/parity"));
|
||||
fs::create_dir_all(&root)
|
||||
.map_err(|error| format!("failed to create {}: {error}", root.display()))?;
|
||||
let worktree = root.join("fluxer-admin-ts-ref-4748f2f1-parent");
|
||||
if !worktree.exists() {
|
||||
run_git(
|
||||
repo_root,
|
||||
&[
|
||||
"worktree",
|
||||
"add",
|
||||
"--detach",
|
||||
path_arg(&worktree).as_str(),
|
||||
TS_REFERENCE_COMMIT,
|
||||
],
|
||||
)?;
|
||||
}
|
||||
validate_worktree(&worktree, &target_commit)?;
|
||||
Ok(worktree)
|
||||
}
|
||||
|
||||
pub fn prepare_reference_package(worktree: &Path) -> Result<(), String> {
|
||||
if env_flag(SKIP_TS_PREPARE_ENV) {
|
||||
return Ok(());
|
||||
}
|
||||
run_command(
|
||||
Command::new("pnpm")
|
||||
.current_dir(worktree)
|
||||
.args(["install", "--frozen-lockfile"]),
|
||||
"pnpm install --frozen-lockfile",
|
||||
)?;
|
||||
run_command(
|
||||
Command::new("pnpm")
|
||||
.current_dir(worktree)
|
||||
.args(["--filter", "@fluxer/config", "generate"]),
|
||||
"pnpm --filter @fluxer/config generate",
|
||||
)?;
|
||||
run_command(
|
||||
Command::new("pnpm")
|
||||
.current_dir(worktree)
|
||||
.args(["--filter", "fluxer_admin", "build:css"]),
|
||||
"pnpm --filter fluxer_admin build:css",
|
||||
)
|
||||
}
|
||||
|
||||
fn validate_worktree(worktree: &Path, target_commit: &str) -> Result<(), String> {
|
||||
if !worktree.join("fluxer_admin/package.json").exists() {
|
||||
return Err(format!(
|
||||
"{} does not look like the TS reference worktree",
|
||||
worktree.display()
|
||||
));
|
||||
}
|
||||
let head = git_stdout(worktree, &["rev-parse", "HEAD"])?;
|
||||
if head != target_commit {
|
||||
return Err(format!(
|
||||
"{} is at {head}, expected {target_commit}",
|
||||
worktree.display()
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_git(repo: &Path, args: &[&str]) -> Result<(), String> {
|
||||
run_command(Command::new("git").current_dir(repo).args(args), "git")
|
||||
}
|
||||
|
||||
fn git_stdout(repo: &Path, args: &[&str]) -> Result<String, String> {
|
||||
let output = Command::new("git")
|
||||
.current_dir(repo)
|
||||
.args(args)
|
||||
.output()
|
||||
.map_err(|error| format!("failed to run git {}: {error}", args.join(" ")))?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"git {} failed\nstdout:\n{}\nstderr:\n{}",
|
||||
args.join(" "),
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
));
|
||||
}
|
||||
Ok(String::from_utf8_lossy(&output.stdout).trim().to_owned())
|
||||
}
|
||||
|
||||
fn run_command(command: &mut Command, label: &str) -> Result<(), String> {
|
||||
let output = command
|
||||
.output()
|
||||
.map_err(|error| format!("failed to run {label}: {error}"))?;
|
||||
if output.status.success() {
|
||||
return Ok(());
|
||||
}
|
||||
Err(format!(
|
||||
"{label} failed with status {}\nstdout:\n{}\nstderr:\n{}",
|
||||
output.status,
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
))
|
||||
}
|
||||
|
||||
fn path_arg(path: &Path) -> String {
|
||||
path.to_string_lossy().into_owned()
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use super::TEST_ADMIN_SECRET;
|
||||
use fluxer_admin::{
|
||||
build_router,
|
||||
config::{AdminConfig, ProxyConfig, RuntimeEnv},
|
||||
};
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::{net::TcpListener, task::JoinHandle, time::sleep};
|
||||
|
||||
pub struct RunningRustAdmin {
|
||||
base_url: String,
|
||||
handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl RunningRustAdmin {
|
||||
pub fn base_url(&self) -> &str {
|
||||
&self.base_url
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RunningRustAdmin {
|
||||
fn drop(&mut self) {
|
||||
self.handle.abort();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(api_endpoint: &str) -> Result<RunningRustAdmin, String> {
|
||||
let listener = TcpListener::bind("127.0.0.1:0")
|
||||
.await
|
||||
.map_err(|error| format!("failed to bind Rust admin server: {error}"))?;
|
||||
let port = listener
|
||||
.local_addr()
|
||||
.map_err(|error| format!("failed to read Rust admin address: {error}"))?
|
||||
.port();
|
||||
let base_url = format!("http://127.0.0.1:{port}");
|
||||
let config = admin_config(port, api_endpoint, &base_url);
|
||||
let router = build_router(config);
|
||||
let handle = tokio::spawn(async move {
|
||||
let _ = axum::serve(listener, router).await;
|
||||
});
|
||||
wait_for_health(&base_url).await?;
|
||||
Ok(RunningRustAdmin { base_url, handle })
|
||||
}
|
||||
|
||||
fn admin_config(port: u16, api_endpoint: &str, admin_endpoint: &str) -> AdminConfig {
|
||||
AdminConfig {
|
||||
env: RuntimeEnv::Test,
|
||||
host: "127.0.0.1".to_owned(),
|
||||
port,
|
||||
secret_key_base: TEST_ADMIN_SECRET.to_owned(),
|
||||
base_path: String::new(),
|
||||
api_endpoint: api_endpoint.to_owned(),
|
||||
media_endpoint: format!("{api_endpoint}/media"),
|
||||
static_cdn_endpoint: "https://static.example.test".to_owned(),
|
||||
admin_endpoint: admin_endpoint.to_owned(),
|
||||
web_app_endpoint: "http://127.0.0.1:8088".to_owned(),
|
||||
kv_url: "redis://127.0.0.1:6379/0".to_owned(),
|
||||
oauth_client_id: "1234567890123456789".to_owned(),
|
||||
oauth_client_secret: "test-admin-oauth-secret".to_owned(),
|
||||
oauth_redirect_uri: format!("{admin_endpoint}/oauth2_callback"),
|
||||
build_version: "parity".to_owned(),
|
||||
release_channel: "parity".to_owned(),
|
||||
self_hosted: false,
|
||||
proxy: ProxyConfig {
|
||||
trust_client_ip_header: false,
|
||||
client_ip_header_name: "x-forwarded-for".to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn wait_for_health(base_url: &str) -> Result<(), String> {
|
||||
let client = reqwest::Client::builder()
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.map_err(|error| format!("failed to build health client: {error}"))?;
|
||||
let deadline = Instant::now() + Duration::from_secs(30);
|
||||
let url = format!("{}/_health", base_url.trim_end_matches('/'));
|
||||
let mut last_error = String::new();
|
||||
while Instant::now() < deadline {
|
||||
match client.get(&url).send().await {
|
||||
Ok(response) if response.status().is_success() => return Ok(()),
|
||||
Ok(response) => last_error = format!("health returned {}", response.status()),
|
||||
Err(error) => last_error = error.to_string(),
|
||||
}
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
}
|
||||
Err(format!("timed out waiting for {url}: {last_error}"))
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use super::TEST_ADMIN_SECRET;
|
||||
use fluxer_admin::{
|
||||
build_router,
|
||||
config::{AdminConfig, ProxyConfig, RuntimeEnv},
|
||||
};
|
||||
use std::{
|
||||
net::TcpListener as StdTcpListener,
|
||||
path::Path,
|
||||
process::{Child, Command, Stdio},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::{net::TcpListener, task::JoinHandle, time::sleep};
|
||||
|
||||
pub struct RunningRustAdmin {
|
||||
base_url: String,
|
||||
handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
pub struct RunningTsAdmin {
|
||||
base_url: String,
|
||||
child: Child,
|
||||
}
|
||||
|
||||
impl RunningRustAdmin {
|
||||
pub fn base_url(&self) -> &str {
|
||||
&self.base_url
|
||||
}
|
||||
}
|
||||
|
||||
impl RunningTsAdmin {
|
||||
pub fn base_url(&self) -> &str {
|
||||
&self.base_url
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RunningRustAdmin {
|
||||
fn drop(&mut self) {
|
||||
self.handle.abort();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RunningTsAdmin {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.child.kill();
|
||||
let _ = self.child.wait();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reserve_local_port() -> Result<u16, String> {
|
||||
let listener = StdTcpListener::bind("127.0.0.1:0")
|
||||
.map_err(|error| format!("failed to reserve local port: {error}"))?;
|
||||
listener
|
||||
.local_addr()
|
||||
.map(|addr| addr.port())
|
||||
.map_err(|error| format!("failed to read reserved local port: {error}"))
|
||||
}
|
||||
|
||||
pub async fn start_rust_admin(api_endpoint: &str) -> Result<RunningRustAdmin, String> {
|
||||
let listener = TcpListener::bind("127.0.0.1:0")
|
||||
.await
|
||||
.map_err(|error| format!("failed to bind Rust admin server: {error}"))?;
|
||||
let port = listener
|
||||
.local_addr()
|
||||
.map_err(|error| format!("failed to read Rust admin address: {error}"))?
|
||||
.port();
|
||||
let base_url = format!("http://127.0.0.1:{port}");
|
||||
let config = admin_config(port, api_endpoint, &base_url);
|
||||
let router = build_router(config);
|
||||
let handle = tokio::spawn(async move {
|
||||
let _ = axum::serve(listener, router).await;
|
||||
});
|
||||
wait_for_health(&base_url).await?;
|
||||
Ok(RunningRustAdmin { base_url, handle })
|
||||
}
|
||||
|
||||
pub async fn start_ts_admin(
|
||||
worktree: &Path,
|
||||
port: u16,
|
||||
api_endpoint: &str,
|
||||
) -> Result<RunningTsAdmin, String> {
|
||||
let base_url = format!("http://127.0.0.1:{port}");
|
||||
let mut command = Command::new("pnpm");
|
||||
command
|
||||
.current_dir(worktree)
|
||||
.args(["--filter", "fluxer_admin", "start"])
|
||||
.env("BUILD_VERSION", "parity")
|
||||
.env("RELEASE_CHANNEL", "parity");
|
||||
for (key, value) in ts_admin_env(port, api_endpoint, &base_url) {
|
||||
command.env(key, value);
|
||||
}
|
||||
let child = command
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.spawn()
|
||||
.map_err(|error| format!("failed to start TS admin server: {error}"))?;
|
||||
let mut server = RunningTsAdmin { base_url, child };
|
||||
if let Err(error) = wait_for_health(server.base_url()).await {
|
||||
let _ = server.child.kill();
|
||||
let _ = server.child.wait();
|
||||
return Err(error);
|
||||
}
|
||||
Ok(server)
|
||||
}
|
||||
|
||||
fn admin_config(port: u16, api_endpoint: &str, admin_endpoint: &str) -> AdminConfig {
|
||||
AdminConfig {
|
||||
env: RuntimeEnv::Test,
|
||||
host: "127.0.0.1".to_owned(),
|
||||
port,
|
||||
secret_key_base: TEST_ADMIN_SECRET.to_owned(),
|
||||
base_path: String::new(),
|
||||
api_endpoint: api_endpoint.to_owned(),
|
||||
media_endpoint: format!("{api_endpoint}/media"),
|
||||
static_cdn_endpoint: "https://static.example.test".to_owned(),
|
||||
admin_endpoint: admin_endpoint.to_owned(),
|
||||
web_app_endpoint: "http://127.0.0.1:8088".to_owned(),
|
||||
kv_url: "redis://127.0.0.1:6379/0".to_owned(),
|
||||
oauth_client_id: "1234567890123456789".to_owned(),
|
||||
oauth_client_secret: "test-admin-oauth-secret".to_owned(),
|
||||
oauth_redirect_uri: format!("{admin_endpoint}/oauth2_callback"),
|
||||
build_version: "parity".to_owned(),
|
||||
release_channel: "parity".to_owned(),
|
||||
self_hosted: false,
|
||||
proxy: ProxyConfig {
|
||||
trust_client_ip_header: false,
|
||||
client_ip_header_name: "x-forwarded-for".to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn ts_admin_env(
|
||||
port: u16,
|
||||
api_endpoint: &str,
|
||||
admin_endpoint: &str,
|
||||
) -> Vec<(&'static str, String)> {
|
||||
vec![
|
||||
("FLUXER_ENV", "test".to_owned()),
|
||||
("NODE_ENV", "production".to_owned()),
|
||||
("FLUXER_BASE_DOMAIN", "127.0.0.1".to_owned()),
|
||||
("FLUXER_PUBLIC_SCHEME", "http".to_owned()),
|
||||
("FLUXER_PUBLIC_PORT", port.to_string()),
|
||||
("FLUXER_API_ENDPOINT", api_endpoint.to_owned()),
|
||||
("FLUXER_ADMIN_ENDPOINT", admin_endpoint.to_owned()),
|
||||
("FLUXER_APP_ENDPOINT", "http://127.0.0.1:8088".to_owned()),
|
||||
("FLUXER_MEDIA_ENDPOINT", format!("{api_endpoint}/media")),
|
||||
(
|
||||
"FLUXER_STATIC_CDN_ENDPOINT",
|
||||
"https://static.example.test".to_owned(),
|
||||
),
|
||||
("FLUXER_CASSANDRA_HOSTS", "127.0.0.1".to_owned()),
|
||||
("FLUXER_CASSANDRA_KEYSPACE", "fluxer_test".to_owned()),
|
||||
("FLUXER_CASSANDRA_LOCAL_DC", "datacenter1".to_owned()),
|
||||
("FLUXER_CASSANDRA_USERNAME", "cassandra".to_owned()),
|
||||
("FLUXER_CASSANDRA_PASSWORD", "cassandra".to_owned()),
|
||||
("FLUXER_KV_URL", "redis://127.0.0.1:6379/0".to_owned()),
|
||||
("FLUXER_S3_ACCESS_KEY_ID", "test".to_owned()),
|
||||
("FLUXER_S3_SECRET_ACCESS_KEY", "test".to_owned()),
|
||||
(
|
||||
"FLUXER_MEDIA_PROXY_SECRET_KEY",
|
||||
"test-media-secret".to_owned(),
|
||||
),
|
||||
("FLUXER_ADMIN_PORT", port.to_string()),
|
||||
("FLUXER_ADMIN_SECRET_KEY_BASE", TEST_ADMIN_SECRET.to_owned()),
|
||||
(
|
||||
"FLUXER_ADMIN_OAUTH_CLIENT_SECRET",
|
||||
"test-admin-oauth-secret".to_owned(),
|
||||
),
|
||||
(
|
||||
"FLUXER_MARKETING_SECRET_KEY_BASE",
|
||||
"test-marketing-secret".to_owned(),
|
||||
),
|
||||
("FLUXER_APP_PROXY_PORT", "8773".to_owned()),
|
||||
(
|
||||
"FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT",
|
||||
format!("{api_endpoint}/media"),
|
||||
),
|
||||
(
|
||||
"FLUXER_GATEWAY_RPC_AUTH_TOKEN",
|
||||
"test-gateway-rpc-token".to_owned(),
|
||||
),
|
||||
("FLUXER_GATEWAY_PUSH_ENABLED", "false".to_owned()),
|
||||
("FLUXER_SUDO_MODE_SECRET", "test-sudo-secret".to_owned()),
|
||||
(
|
||||
"FLUXER_CONNECTION_INITIATION_SECRET",
|
||||
"test-connection-secret".to_owned(),
|
||||
),
|
||||
(
|
||||
"FLUXER_VAPID_PUBLIC_KEY",
|
||||
"test-vapid-public-key".to_owned(),
|
||||
),
|
||||
(
|
||||
"FLUXER_VAPID_PRIVATE_KEY",
|
||||
"test-vapid-private-key".to_owned(),
|
||||
),
|
||||
("FLUXER_VAPID_EMAIL", "[email protected]".to_owned()),
|
||||
("FLUXER_EMAIL_ENABLED", "false".to_owned()),
|
||||
("FLUXER_LIVEKIT_ENABLED", "false".to_owned()),
|
||||
("FLUXER_STRIPE_ENABLED", "true".to_owned()),
|
||||
("FLUXER_SEARCH_URL", "http://127.0.0.1:9200".to_owned()),
|
||||
("FLUXER_SEARCH_API_KEY", "test".to_owned()),
|
||||
("FLUXER_CAPTCHA_ENABLED", "false".to_owned()),
|
||||
("FLUXER_CAPTCHA_PROVIDER", "none".to_owned()),
|
||||
("FLUXER_SELF_HOSTED", "false".to_owned()),
|
||||
("FLUXER_DISCOVERY_ENABLED", "true".to_owned()),
|
||||
("FLUXER_DISABLE_RATE_LIMITS", "true".to_owned()),
|
||||
("FLUXER_TEST_MODE_ENABLED", "true".to_owned()),
|
||||
]
|
||||
}
|
||||
|
||||
async fn wait_for_health(base_url: &str) -> Result<(), String> {
|
||||
let client = reqwest::Client::builder()
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.map_err(|error| format!("failed to build health client: {error}"))?;
|
||||
let deadline = Instant::now() + Duration::from_secs(30);
|
||||
let url = format!("{}/_health", base_url.trim_end_matches('/'));
|
||||
let mut last_error = String::new();
|
||||
while Instant::now() < deadline {
|
||||
match client.get(&url).send().await {
|
||||
Ok(response) if response.status().is_success() => return Ok(()),
|
||||
Ok(response) => {
|
||||
last_error = format!("health returned {}", response.status());
|
||||
}
|
||||
Err(error) => {
|
||||
last_error = error.to_string();
|
||||
}
|
||||
}
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
}
|
||||
Err(format!("timed out waiting for {url}: {last_error}"))
|
||||
}
|
||||
Reference in New Issue
Block a user