summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorConrad Ludgate <conradludgate@gmail.com>2023-09-29 02:56:40 +0100
committerGitHub <noreply@github.com>2023-09-28 18:56:40 -0700
commit7067d772bc8c7e3c829a0b43ff9b5579bc07aef3 (patch)
tree731b44997e3ffc86ddc527ffb87827bd8ab9cea1
parent71fd31ed4f2af12184465b9748d167c4485f516e (diff)
fix sync timestamps (#1258)
* fix timestamp * add sync test * skip all sync tests
-rw-r--r--atuin-client/src/api_client.rs2
-rw-r--r--atuin-server-postgres/src/lib.rs33
-rw-r--r--atuin-server-postgres/src/wrappers.rs9
-rw-r--r--atuin.nix3
-rw-r--r--atuin/tests/sync.rs101
5 files changed, 124 insertions, 24 deletions
diff --git a/atuin-client/src/api_client.rs b/atuin-client/src/api_client.rs
index fbeea9aa..ef966f5c 100644
--- a/atuin-client/src/api_client.rs
+++ b/atuin-client/src/api_client.rs
@@ -109,7 +109,7 @@ pub async fn latest_version() -> Result<Version> {
impl<'a> Client<'a> {
pub fn new(
sync_addr: &'a str,
- session_token: &'a str,
+ session_token: &str,
connect_timeout: u64,
timeout: u64,
) -> Result<Self> {
diff --git a/atuin-server-postgres/src/lib.rs b/atuin-server-postgres/src/lib.rs
index 8f473d52..c71d03ae 100644
--- a/atuin-server-postgres/src/lib.rs
+++ b/atuin-server-postgres/src/lib.rs
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPoolOptions;
use sqlx::Row;
-use time::{OffsetDateTime, PrimitiveDateTime};
+use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset};
use tracing::instrument;
use wrappers::{DbHistory, DbRecord, DbSession, DbUser};
@@ -215,8 +215,8 @@ impl Database for Postgres {
)
.bind(user.id)
.bind(host)
- .bind(created_after)
- .bind(since)
+ .bind(into_utc(created_after))
+ .bind(into_utc(since))
.bind(page_size)
.fetch(&self.pool)
.map_ok(|DbHistory(h)| h)
@@ -450,3 +450,30 @@ impl Database for Postgres {
Ok(res)
}
}
+
+fn into_utc(x: OffsetDateTime) -> PrimitiveDateTime {
+ let x = x.to_offset(UtcOffset::UTC);
+ PrimitiveDateTime::new(x.date(), x.time())
+}
+
+#[cfg(test)]
+mod tests {
+ use time::macros::datetime;
+
+ use crate::into_utc;
+
+ #[test]
+ fn utc() {
+ let dt = datetime!(2023-09-26 15:11:02 +05:30);
+ assert_eq!(into_utc(dt), datetime!(2023-09-26 09:41:02));
+ assert_eq!(into_utc(dt).assume_utc(), dt);
+
+ let dt = datetime!(2023-09-26 15:11:02 -07:00);
+ assert_eq!(into_utc(dt), datetime!(2023-09-26 22:11:02));
+ assert_eq!(into_utc(dt).assume_utc(), dt);
+
+ let dt = datetime!(2023-09-26 15:11:02 +00:00);
+ assert_eq!(into_utc(dt), datetime!(2023-09-26 15:11:02));
+ assert_eq!(into_utc(dt).assume_utc(), dt);
+ }
+}
diff --git a/atuin-server-postgres/src/wrappers.rs b/atuin-server-postgres/src/wrappers.rs
index 8bd482b1..b4ae48ae 100644
--- a/atuin-server-postgres/src/wrappers.rs
+++ b/atuin-server-postgres/src/wrappers.rs
@@ -2,6 +2,7 @@ use ::sqlx::{FromRow, Result};
use atuin_common::record::{EncryptedData, Record};
use atuin_server_database::models::{History, Session, User};
use sqlx::{postgres::PgRow, Row};
+use time::PrimitiveDateTime;
pub struct DbUser(pub User);
pub struct DbSession(pub Session);
@@ -36,9 +37,13 @@ impl<'a> ::sqlx::FromRow<'a, PgRow> for DbHistory {
client_id: row.try_get("client_id")?,
user_id: row.try_get("user_id")?,
hostname: row.try_get("hostname")?,
- timestamp: row.try_get("timestamp")?,
+ timestamp: row
+ .try_get::<PrimitiveDateTime, _>("timestamp")?
+ .assume_utc(),
data: row.try_get("data")?,
- created_at: row.try_get("created_at")?,
+ created_at: row
+ .try_get::<PrimitiveDateTime, _>("created_at")?
+ .assume_utc(),
}))
}
}
diff --git a/atuin.nix b/atuin.nix
index 795e927d..fa6d229d 100644
--- a/atuin.nix
+++ b/atuin.nix
@@ -37,7 +37,8 @@ rustPlatform.buildRustPackage {
# Additional flags passed to the cargo test binary, see `cargo test -- --help`
checkFlags = [
- # Registration tests require a postgres server
+ # Sync tests require a postgres server
+ "--skip=sync"
"--skip=registration"
];
diff --git a/atuin/tests/sync.rs b/atuin/tests/sync.rs
index ab1eb420..6dbc7244 100644
--- a/atuin/tests/sync.rs
+++ b/atuin/tests/sync.rs
@@ -1,10 +1,11 @@
use std::{env, net::TcpListener, time::Duration};
use atuin_client::api_client;
-use atuin_common::utils::uuid_v7;
+use atuin_common::{api::AddHistoryRequest, utils::uuid_v7};
use atuin_server::{launch_with_listener, Settings as ServerSettings};
use atuin_server_postgres::{Postgres, PostgresSettings};
use futures_util::TryFutureExt;
+use time::OffsetDateTime;
use tokio::{sync::oneshot, task::JoinHandle};
use tracing::{dispatcher, Dispatch};
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
@@ -19,7 +20,7 @@ async fn start_server(path: &str) -> (String, oneshot::Sender<()>, JoinHandle<()
let dispatch: Dispatch = tracing_subscriber::registry()
.with(formatting_layer)
- .with(EnvFilter::new("atuin_server=debug,info"))
+ .with(EnvFilter::new("atuin_server=debug,atuin_client=debug,info"))
.into();
let db_uri = env::var("ATUIN_DB_URI")
@@ -62,37 +63,103 @@ async fn start_server(path: &str) -> (String, oneshot::Sender<()>, JoinHandle<()
(format!("http://{addr}{path}"), shutdown_tx, server)
}
+async fn register_inner<'a>(
+ address: &'a str,
+ username: &str,
+ password: &str,
+) -> api_client::Client<'a> {
+ let email = format!("{}@example.com", uuid_v7().as_simple());
+
+ // registration works
+ let registration_response = api_client::register(address, username, &email, password)
+ .await
+ .unwrap();
+
+ api_client::Client::new(address, &registration_response.session, 5, 30).unwrap()
+}
+
+async fn login(address: &str, username: String, password: String) -> api_client::Client<'_> {
+ // registration works
+ let login_respose = api_client::login(
+ address,
+ atuin_common::api::LoginRequest { username, password },
+ )
+ .await
+ .unwrap();
+
+ api_client::Client::new(address, &login_respose.session, 5, 30).unwrap()
+}
+
+async fn register(address: &str) -> api_client::Client<'_> {
+ let username = uuid_v7().as_simple().to_string();
+ let password = uuid_v7().as_simple().to_string();
+ register_inner(address, &username, &password).await
+}
+
#[tokio::test]
async fn registration() {
let path = format!("/{}", uuid_v7().as_simple());
let (address, shutdown, server) = start_server(&path).await;
dbg!(&address);
+ // -- REGISTRATION --
+
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();
+ let client = register_inner(&address, &username, &password).await;
- // registration works
- let registration_response = api_client::register(&address, &username, &email, &password)
- .await
- .unwrap();
+ // the session token works
+ let status = client.status().await.unwrap();
+ assert_eq!(status.username, username);
+
+ // -- LOGIN --
- let client = api_client::Client::new(&address, &registration_response.session, 5, 30).unwrap();
+ let client = login(&address, username.clone(), password).await;
// 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();
+ shutdown.send(()).unwrap();
+ server.await.unwrap();
+}
+
+#[tokio::test]
+async fn sync() {
+ let path = format!("/{}", uuid_v7().as_simple());
+ let (address, shutdown, server) = start_server(&path).await;
+
+ let client = register(&address).await;
+ let hostname = uuid_v7().as_simple().to_string();
+ let now = OffsetDateTime::now_utc();
+
+ let data1 = uuid_v7().as_simple().to_string();
+ let data2 = uuid_v7().as_simple().to_string();
+
+ client
+ .post_history(&[
+ AddHistoryRequest {
+ id: uuid_v7().as_simple().to_string(),
+ timestamp: now,
+ data: data1.clone(),
+ hostname: hostname.clone(),
+ },
+ AddHistoryRequest {
+ id: uuid_v7().as_simple().to_string(),
+ timestamp: now,
+ data: data2.clone(),
+ hostname: hostname.clone(),
+ },
+ ])
+ .await
+ .unwrap();
+
+ let history = client
+ .get_history(OffsetDateTime::UNIX_EPOCH, OffsetDateTime::UNIX_EPOCH, None)
+ .await
+ .unwrap();
- // currently we return the same session token
- assert_eq!(registration_response.session, login_response.session);
+ assert_eq!(history.history, vec![data1, data2]);
shutdown.send(()).unwrap();
server.await.unwrap();