some simple server tests (#1096)

* some simple server tests

* fmt

* logging in server test

* log server errors

* fix postgres uri

* postgres ports

* localhost again?

* Rebase fixes

---------

Co-authored-by: Ellie Huxtable <ellie@elliehuxtable.com>
This commit is contained in:
Conrad Ludgate 2023-07-27 09:34:13 +01:00 committed by GitHub
parent c0449955e3
commit c10ba684e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 8 deletions

View file

@ -19,7 +19,7 @@ jobs:
- name: Run nix flake check - name: Run nix flake check
run: nix flake check --print-build-logs run: nix flake check --print-build-logs
build: build-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View file

@ -44,6 +44,16 @@ jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_USER: atuin
POSTGRES_PASSWORD: pass
POSTGRES_DB: atuin
ports:
- 5432:5432
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -62,6 +72,8 @@ jobs:
- name: Run cargo test - name: Run cargo test
run: cargo test --all-features --workspace run: cargo test --all-features --workspace
env:
ATUIN_DB_URI: postgres://atuin:pass@localhost:5432/atuin
- name: Run cargo check (all features) - name: Run cargo check (all features)
run: cargo check --all-features --workspace run: cargo check --all-features --workspace

33
Cargo.lock generated
View file

@ -111,7 +111,9 @@ dependencies = [
"serde_json", "serde_json",
"tiny-bip39", "tiny-bip39",
"tokio", "tokio",
"tracing",
"tracing-subscriber", "tracing-subscriber",
"tracing-tree",
"unicode-width", "unicode-width",
"whoami", "whoami",
] ]
@ -2947,6 +2949,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log",
"tracing-core",
] ]
[[package]] [[package]]
@ -2965,6 +2979,19 @@ dependencies = [
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-tree"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d6b63348fad3ae0439b8bebf8d38fb5bda0b115d7a8a7e6f165f12790c58c3"
dependencies = [
"is-terminal",
"nu-ansi-term",
"tracing-core",
"tracing-log",
"tracing-subscriber",
]
[[package]] [[package]]
name = "try-lock" name = "try-lock"
version = "0.2.3" version = "0.2.3"
@ -3070,6 +3097,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"

View file

@ -1,6 +1,9 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use std::net::{IpAddr, SocketAddr}; use std::{
future::Future,
net::{IpAddr, SocketAddr, TcpListener},
};
use atuin_server_database::Database; use atuin_server_database::Database;
use axum::Server; use axum::Server;
@ -16,10 +19,15 @@ use tokio::signal;
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
async fn shutdown_signal() { async fn shutdown_signal() {
signal::unix::signal(signal::unix::SignalKind::terminate()) let mut term = signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to register signal handler") .expect("failed to register signal handler");
.recv() let mut interrupt = signal::unix::signal(signal::unix::SignalKind::interrupt())
.await; .expect("failed to register signal handler");
tokio::select! {
_ = term.recv() => {},
_ = interrupt.recv() => {},
};
eprintln!("Shutting down gracefully..."); eprintln!("Shutting down gracefully...");
} }
@ -38,16 +46,29 @@ pub async fn launch<Db: Database>(
port: u16, port: u16,
) -> Result<()> { ) -> Result<()> {
let host = host.parse::<IpAddr>()?; let host = host.parse::<IpAddr>()?;
launch_with_listener::<Db>(
settings,
TcpListener::bind(SocketAddr::new(host, port)).context("could not connect to socket")?,
shutdown_signal(),
)
.await
}
pub async fn launch_with_listener<Db: Database>(
settings: Settings<Db::Settings>,
listener: TcpListener,
shutdown: impl Future<Output = ()>,
) -> Result<()> {
let db = Db::new(&settings.db_settings) let db = Db::new(&settings.db_settings)
.await .await
.wrap_err_with(|| format!("failed to connect to db: {:?}", settings.db_settings))?; .wrap_err_with(|| format!("failed to connect to db: {:?}", settings.db_settings))?;
let r = router::router(db, settings); let r = router::router(db, settings);
Server::bind(&SocketAddr::new(host, port)) Server::from_tcp(listener)
.context("could not launch server")?
.serve(r.into_make_service()) .serve(r.into_make_service())
.with_graceful_shutdown(shutdown_signal()) .with_graceful_shutdown(shutdown)
.await?; .await?;
Ok(()) Ok(())

View file

@ -71,9 +71,14 @@ futures-util = "0.3"
fuzzy-matcher = "0.3.7" fuzzy-matcher = "0.3.7"
colored = "2.0.4" colored = "2.0.4"
ratatui = "0.21" ratatui = "0.21"
tracing = "0.1"
[dependencies.tracing-subscriber] [dependencies.tracing-subscriber]
version = "0.3" version = "0.3"
default-features = false default-features = false
features = ["ansi", "fmt", "registry", "env-filter"] features = ["ansi", "fmt", "registry", "env-filter"]
optional = true optional = true
[dev-dependencies]
tracing-tree = "0.2"

99
atuin/tests/sync.rs Normal file
View file

@ -0,0 +1,99 @@
use std::{env, net::TcpListener, time::Duration};
use atuin_client::api_client;
use atuin_common::utils::uuid_v7;
use atuin_server::{launch_with_listener, Settings as ServerSettings};
use atuin_server_postgres::{Postgres, PostgresSettings};
use futures_util::TryFutureExt;
use tokio::{sync::oneshot, task::JoinHandle};
use tracing::{dispatcher, Dispatch};
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
async fn start_server(path: &str) -> (String, oneshot::Sender<()>, JoinHandle<()>) {
let formatting_layer = tracing_tree::HierarchicalLayer::default()
.with_writer(tracing_subscriber::fmt::TestWriter::new())
.with_indent_lines(true)
.with_ansi(true)
.with_targets(true)
.with_indent_amount(2);
let dispatch: Dispatch = tracing_subscriber::registry()
.with(formatting_layer)
.with(EnvFilter::new("atuin_server=debug,info"))
.into();
let db_uri = env::var("ATUIN_DB_URI")
.unwrap_or_else(|_| "postgres://atuin:pass@localhost:5432/atuin".to_owned());
let server_settings = ServerSettings {
host: "127.0.0.1".to_owned(),
port: 0,
path: path.to_owned(),
open_registration: true,
max_history_length: 8192,
max_record_size: 1024 * 1024 * 1024,
page_size: 1100,
register_webhook_url: None,
register_webhook_username: String::new(),
db_settings: PostgresSettings { db_uri },
};
let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel();
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let _tracing_guard = dispatcher::set_default(&dispatch);
if let Err(e) = launch_with_listener::<Postgres>(
server_settings,
listener,
shutdown_rx.unwrap_or_else(|_| ()),
)
.await
{
tracing::error!(error=?e, "server error");
panic!("error running server: {e:?}");
}
});
// let the server come online
tokio::time::sleep(Duration::from_millis(200)).await;
(format!("http://{addr}{path}"), shutdown_tx, server)
}
#[tokio::test]
async fn registration() {
let path = format!("/{}", uuid_v7().as_simple());
let (address, shutdown, server) = start_server(&path).await;
dbg!(&address);
let username = uuid_v7().as_simple().to_string();
let email = format!("{}@example.com", uuid_v7().as_simple());
let password = uuid_v7().as_simple().to_string();
// registration works
let registration_response = api_client::register(&address, &username, &email, &password)
.await
.unwrap();
let client = api_client::Client::new(&address, &registration_response.session).unwrap();
// the session token works
let status = client.status().await.unwrap();
assert_eq!(status.username, username);
// login works
let login_response = api_client::login(
&address,
atuin_common::api::LoginRequest { username, password },
)
.await
.unwrap();
// currently we return the same session token
assert_eq!(registration_response.session, login_response.session);
shutdown.send(()).unwrap();
server.await.unwrap();
}