test: Add minimal test binary to verify Docker execution
Some checks failed
Lint and Build / Lint (push) Failing after 5s
Lint and Build / Build (push) Has been skipped
Lint and Build / Docker Build (push) Has been skipped

This commit is contained in:
goose 2026-02-22 10:58:15 -03:00
parent e555813290
commit 177f2ad8e7

View file

@ -1,181 +1,28 @@
mod config;
mod db;
mod models;
mod auth;
mod handlers;
mod middleware;
use axum::{
routing::{get, post, put, delete},
Router,
middleware as axum_middleware,
};
use tower::ServiceBuilder;
use tower_http::{
cors::CorsLayer,
trace::TraceLayer,
};
use config::Config;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
// Helper function to log to both file and stdout fn main() {
fn log(msg: &str) { let msg = format!("BINARY STARTED: {}\n", chrono::Utc::now().to_rfc3339());
let timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S%.3f");
let full_msg = format!("[{}] {}\n", timestamp, msg);
// Try to write to file // Try to write to file
if let Ok(mut file) = OpenOptions::new() if let Ok(mut file) = OpenOptions::new()
.create(true) .create(true)
.append(true) .write(true)
.open("/tmp/normogen-startup.log") .truncate(true)
.open("/tmp/test-startup.log")
{ {
let _ = file.write_all(full_msg.as_bytes()); let _ = file.write_all(msg.as_bytes());
let _ = file.flush(); let _ = file.flush();
} }
// Also print to stdout // Try to print to stdout
print!("{}", full_msg); println!("BINARY STARTED");
let _ = std::io::stdout().flush(); let _ = std::io::stdout().flush();
}
// Try to print to stderr
// Wrapper to catch when main returns eprintln!("BINARY STARTED (stderr)");
async fn run() -> anyhow::Result<()> { let _ = std::io::stderr().flush();
log("=== NORMOGEN STARTING ===");
log("[1/7] Loading environment variables..."); // Sleep to keep container alive
std::thread::sleep(std::time::Duration::from_secs(60));
match dotenv::dotenv() {
Ok(path) => {
log(&format!("[1/7] Loaded .env from: {:?}", path));
}
Err(_) => {
log("[1/7] No .env file found (OK in Docker)");
}
}
log("[2/7] Initializing logging...");
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "normogen_backend=debug,tower_http=debug,axum=debug".into())
)
.init();
log("[3/7] Loading configuration...");
let config = match Config::from_env() {
Ok(cfg) => {
log(&format!("[3/7] Config loaded: DB={}, Port={}", cfg.database.database, cfg.server.port));
cfg
}
Err(e) => {
log(&format!("[FATAL] Failed to load configuration: {}", e));
return Err(e);
}
};
log(&format!("[4/7] Connecting to MongoDB at {}...", config.database.uri));
log("[4/7] Starting MongoDB connection (this may hang)...");
let db = match db::MongoDb::new(&config.database.uri, &config.database.database).await {
Ok(db) => {
log("[4/7] MongoDB connection successful!");
db
}
Err(e) => {
log(&format!("[FATAL] Failed to connect to MongoDB: {}", e));
return Err(e);
}
};
log("[5/7] Performing health check...");
match db.health_check().await {
Ok(_) => {
log("[5/7] MongoDB health check: OK");
}
Err(e) => {
log(&format!("[FATAL] MongoDB health check failed: {}", e));
return Err(e);
}
}
log("[6/7] Building application...");
let jwt_service = auth::JwtService::new(config.jwt.clone());
let app_state = config::AppState {
db,
jwt_service,
config: config.clone(),
};
let public_routes = Router::new()
.route("/health", get(handlers::health_check))
.route("/ready", get(handlers::ready_check))
.route("/api/auth/register", post(handlers::register))
.route("/api/auth/login", post(handlers::login))
.route("/api/auth/recover-password", post(handlers::recover_password))
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(CorsLayer::new())
);
let protected_routes = Router::new()
.route("/api/users/me", get(handlers::get_profile))
.route("/api/users/me", put(handlers::update_profile))
.route("/api/users/me", delete(handlers::delete_account))
.route("/api/users/me/settings", get(handlers::get_settings))
.route("/api/users/me/settings", put(handlers::update_settings))
.route("/api/users/me/change-password", post(handlers::change_password))
.route("/api/shares", post(handlers::create_share))
.route("/api/shares", get(handlers::list_shares))
.route("/api/shares/:id", get(handlers::get_share))
.route("/api/shares/:id", put(handlers::update_share))
.route("/api/shares/:id", delete(handlers::delete_share))
.route("/api/permissions/check", post(handlers::check_permission))
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(CorsLayer::new())
)
.route_layer(axum_middleware::from_fn_with_state(
app_state.clone(),
crate::middleware::auth::jwt_auth_middleware
));
let app = public_routes.merge(protected_routes).with_state(app_state);
log(&format!("[7/7] Starting server on {}:{}...", config.server.host, config.server.port));
let listener = tokio::net::TcpListener::bind(&format!("{}:{}", config.server.host, config.server.port))
.await?;
log("=== SERVER READY ===");
log(&format!("Listening on http://{}:{}", config.server.host, config.server.port));
log("About to call axum::serve (this blocks forever)...");
tracing::info!("Server listening on {}:{}", config.server.host, config.server.port);
// This should block forever
axum::serve(listener, app).await?;
// This should never be reached
log("[UNEXPECTED] Server stopped!");
Ok(())
}
#[tokio::main]
async fn main() {
log("MAIN ENTERED");
let result = run().await;
log(&format!("MAIN EXITING: {:?}", result));
std::process::exit(match result {
Ok(_) => {
log("EXIT CODE 0");
0
}
Err(e) => {
log(&format!("EXIT CODE 1: {}", e));
1
}
});
} }