aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/nix.yml2
-rw-r--r--.github/workflows/rust.yml12
-rw-r--r--Cargo.lock33
-rw-r--r--atuin-server/src/lib.rs35
-rw-r--r--atuin/Cargo.toml5
-rw-r--r--atuin/tests/sync.rs99
6 files changed, 178 insertions, 8 deletions
diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml
index 3e5483bd..6903650a 100644
--- a/.github/workflows/nix.yml
+++ b/.github/workflows/nix.yml
@@ -19,7 +19,7 @@ jobs:
- name: Run nix flake check
run: nix flake check --print-build-logs
- build:
+ build-test:
runs-on: ubuntu-latest
steps:
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index d8411fc1..4b553f3e 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -44,6 +44,16 @@ jobs:
test:
runs-on: ubuntu-latest
+ services:
+ postgres:
+ image: postgres
+ env:
+ POSTGRES_USER: atuin
+ POSTGRES_PASSWORD: pass
+ POSTGRES_DB: atuin
+ ports:
+ - 5432:5432
+
steps:
- uses: actions/checkout@v3
@@ -62,6 +72,8 @@ jobs:
- name: Run cargo test
run: cargo test --all-features --workspace
+ env:
+ ATUIN_DB_URI: postgres://atuin:pass@localhost:5432/atuin
- name: Run cargo check (all features)
run: cargo check --all-features --workspace
diff --git a/Cargo.lock b/Cargo.lock
index bd122b35..afb4318f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -111,7 +111,9 @@ dependencies = [
"serde_json",
"tiny-bip39",
"tokio",
+ "tracing",
"tracing-subscriber",
+ "tracing-tree",
"unicode-width",
"whoami",
]
@@ -2947,6 +2949,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"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]]
@@ -2966,6 +2980,19 @@ dependencies = [
]
[[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]]
name = "try-lock"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3071,6 +3098,12 @@ dependencies = [
]
[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/atuin-server/src/lib.rs b/atuin-server/src/lib.rs
index fc4d9e0c..810b7db9 100644
--- a/atuin-server/src/lib.rs
+++ b/atuin-server/src/lib.rs
@@ -1,6 +1,9 @@
#![forbid(unsafe_code)]
-use std::net::{IpAddr, SocketAddr};
+use std::{
+ future::Future,
+ net::{IpAddr, SocketAddr, TcpListener},
+};
use atuin_server_database::Database;
use axum::Server;
@@ -16,10 +19,15 @@ use tokio::signal;
#[cfg(target_family = "unix")]
async fn shutdown_signal() {
- signal::unix::signal(signal::unix::SignalKind::terminate())
- .expect("failed to register signal handler")
- .recv()
- .await;
+ let mut term = signal::unix::signal(signal::unix::SignalKind::terminate())
+ .expect("failed to register signal handler");
+ let mut interrupt = signal::unix::signal(signal::unix::SignalKind::interrupt())
+ .expect("failed to register signal handler");
+
+ tokio::select! {
+ _ = term.recv() => {},
+ _ = interrupt.recv() => {},
+ };
eprintln!("Shutting down gracefully...");
}
@@ -38,16 +46,29 @@ pub async fn launch<Db: Database>(
port: u16,
) -> Result<()> {
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)
.await
.wrap_err_with(|| format!("failed to connect to db: {:?}", settings.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())
- .with_graceful_shutdown(shutdown_signal())
+ .with_graceful_shutdown(shutdown)
.await?;
Ok(())
diff --git a/atuin/Cargo.toml b/atuin/Cargo.toml
index 43989186..551a1f16 100644
--- a/atuin/Cargo.toml
+++ b/atuin/Cargo.toml
@@ -71,9 +71,14 @@ futures-util = "0.3"
fuzzy-matcher = "0.3.7"
colored = "2.0.4"
ratatui = "0.21"
+tracing = "0.1"
+
[dependencies.tracing-subscriber]
version = "0.3"
default-features = false
features = ["ansi", "fmt", "registry", "env-filter"]
optional = true
+
+[dev-dependencies]
+tracing-tree = "0.2"
diff --git a/atuin/tests/sync.rs b/atuin/tests/sync.rs
new file mode 100644
index 00000000..35aa35bb
--- /dev/null
+++ b/atuin/tests/sync.rs
@@ -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();
+}