diff --git a/Cargo.lock b/Cargo.lock index 904d307d..741c219e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -811,6 +811,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto-future" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1e7e457ea78e524f48639f551fd79703ac3f2237f5ecccdf4708f8a75ad373" + [[package]] name = "auto_impl" version = "1.2.0" @@ -877,6 +883,31 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-test" +version = "13.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deffdcc6ae7bc024b82f4bd3f46b048781a504588e86716a6d5ccc10b2615e99" +dependencies = [ + "anyhow", + "async-trait", + "auto-future", + "axum", + "bytes", + "cookie", + "http 0.2.12", + "hyper 0.14.28", + "pretty_assertions", + "reserve-port", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "tokio", + "tower", + "url", +] + [[package]] name = "backtrace" version = "0.3.71" @@ -1120,9 +1151,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" dependencies = [ "serde", ] @@ -1347,6 +1378,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1615,6 +1656,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.9.0" @@ -2492,6 +2539,7 @@ dependencies = [ "anyhow", "askama", "axum", + "axum-test", "chrono", "clap 4.5.4", "enr", @@ -3622,13 +3670,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4106,6 +4155,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "primitive-types" version = "0.10.1" @@ -4457,6 +4516,16 @@ dependencies = [ "winreg", ] +[[package]] +name = "reserve-port" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9838134a2bfaa8e1f40738fcc972ac799de6e0e06b5157acb95fc2b05a0ea283" +dependencies = [ + "lazy_static", + "thiserror", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -5776,28 +5845,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot 0.12.2", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -5956,15 +6024,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -6711,6 +6779,12 @@ dependencies = [ "tap", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.7.34" diff --git a/glados-web/Cargo.toml b/glados-web/Cargo.toml index f9d95b44..8ef3e566 100644 --- a/glados-web/Cargo.toml +++ b/glados-web/Cargo.toml @@ -27,3 +27,6 @@ serde.workspace = true tokio.workspace = true tower-http = { version = "0.3.5", features = ["fs"] } tracing.workspace = true + +[dev-dependencies] +axum-test = "13.4.1" diff --git a/glados-web/assets/favicon.ico b/glados-web/assets/favicon.ico new file mode 100644 index 00000000..798e580c Binary files /dev/null and b/glados-web/assets/favicon.ico differ diff --git a/glados-web/src/lib.rs b/glados-web/src/lib.rs index 2ab343d6..3fd174c3 100644 --- a/glados-web/src/lib.rs +++ b/glados-web/src/lib.rs @@ -2,7 +2,6 @@ use std::sync::Arc; use std::{net::SocketAddr, path::Path}; use anyhow::{bail, Result}; -use axum::http::{StatusCode, Uri}; use axum::{ extract::Extension, routing::{get, get_service}, @@ -25,7 +24,7 @@ const SOCKET: &str = "0.0.0.0:3001"; const ASSET_PATH_ENV_VAR: &str = "GLADOS_WEB_ASSETS_PATH"; -pub async fn run_glados_web(config: Arc) -> Result<()> { +async fn build_router(config: Arc) -> Result { let assets_path = match std::env::var(ASSET_PATH_ENV_VAR) { Ok(path) => Path::new(&path).to_path_buf(), Err(_) => { @@ -41,27 +40,8 @@ pub async fn run_glados_web(config: Arc) -> Result<()> { let serve_dir = get_service(ServeDir::new(assets_path)).handle_error(routes::handle_error); - let nodes_with_zero_high_bits = entity::node::Entity::find() - .filter(entity::node::Column::NodeIdHigh.eq(0)) - .all(&config.database_connection) - .await - .unwrap(); - - info!(rows=?nodes_with_zero_high_bits.len(), "One time migration: setting high bits for node model"); - - for node_model in nodes_with_zero_high_bits { - let raw_node_id = U256::from_be_slice(&node_model.get_node_id().raw()); - let node_id_high: i64 = raw_node_id.wrapping_shr(193).to::(); - - let mut node: entity::node::ActiveModel = node_model.into(); - let previous_value = node.node_id_high; - node.node_id_high = Set(node_id_high); - let updated = node.update(&config.database_connection).await?; - info!(row.id=?updated.id, old=?previous_value, new=?updated.node_id_high, "Setting high bits"); - } - // setup router - let app = Router::new() + Ok(Router::new() .route("/", get(routes::network_overview)) .route("/census/census-list/", get(routes::census_explorer_list)) .route("/census/", get(routes::single_census_view)) @@ -99,10 +79,30 @@ pub async fn run_glados_web(config: Arc) -> Result<()> { ) .nest_service("/static/", serve_dir.clone()) .fallback_service(serve_dir) - .layer(Extension(config)); + .layer(Extension(config))) +} - let app = app.fallback(handler_404); +pub async fn run_glados_web(config: Arc) -> Result<()> { + let nodes_with_zero_high_bits = entity::node::Entity::find() + .filter(entity::node::Column::NodeIdHigh.eq(0)) + .all(&config.database_connection) + .await + .unwrap(); + + info!(rows=?nodes_with_zero_high_bits.len(), "One time migration: setting high bits for node model"); + + for node_model in nodes_with_zero_high_bits { + let raw_node_id = U256::from_be_slice(&node_model.get_node_id().raw()); + let node_id_high: i64 = raw_node_id.wrapping_shr(193).to::(); + + let mut node: entity::node::ActiveModel = node_model.into(); + let previous_value = node.node_id_high; + node.node_id_high = Set(node_id_high); + let updated = node.update(&config.database_connection).await?; + info!(row.id=?updated.id, old=?previous_value, new=?updated.node_id_high, "Setting high bits"); + } + let app = build_router(config).await?; let socket: SocketAddr = SOCKET.parse()?; info!("Serving glados-web at {}", socket); Ok(axum::Server::bind(&socket) @@ -110,8 +110,20 @@ pub async fn run_glados_web(config: Arc) -> Result<()> { .await?) } -/// Global routing error handler to prevent panics. -async fn handler_404(uri: Uri) -> StatusCode { - tracing::error!("404: Nothing to serve for '{uri}'"); - StatusCode::NOT_FOUND +#[cfg(test)] +mod tests { + use super::*; + use axum_test::TestServer; + + #[tokio::test] + async fn test_root_routing() { + // Confirm that basic routing from the root works by loading the favicon + let config = Arc::new(State { + database_connection: Default::default(), + }); + let router = build_router(config).await.unwrap(); + let server = TestServer::new(router).unwrap(); + let response = server.get("/favicon.ico").await; + response.assert_status_ok(); + } }