Skip to content

Commit

Permalink
fix sync timestamps (atuinsh#1258)
Browse files Browse the repository at this point in the history
* fix timestamp

* add sync test

* skip all sync tests
  • Loading branch information
conradludgate authored Sep 29, 2023
1 parent 71fd31e commit 7067d77
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 24 deletions.
2 changes: 1 addition & 1 deletion atuin-client/src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
33 changes: 30 additions & 3 deletions atuin-server-postgres/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
}
9 changes: 7 additions & 2 deletions atuin-server-postgres/src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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(),
}))
}
}
Expand Down
3 changes: 2 additions & 1 deletion atuin.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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"
];

Expand Down
101 changes: 84 additions & 17 deletions atuin/tests/sync.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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")
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 7067d77

Please sign in to comment.