fix sync timestamps (#1258)

* fix timestamp

* add sync test

* skip all sync tests
This commit is contained in:
Conrad Ludgate 2023-09-29 02:56:40 +01:00 committed by GitHub
parent 71fd31ed4f
commit 7067d772bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 126 additions and 26 deletions

View file

@ -109,7 +109,7 @@ pub async fn latest_version() -> Result<Version> {
impl<'a> Client<'a> { impl<'a> Client<'a> {
pub fn new( pub fn new(
sync_addr: &'a str, sync_addr: &'a str,
session_token: &'a str, session_token: &str,
connect_timeout: u64, connect_timeout: u64,
timeout: u64, timeout: u64,
) -> Result<Self> { ) -> Result<Self> {

View file

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPoolOptions; use sqlx::postgres::PgPoolOptions;
use sqlx::Row; use sqlx::Row;
use time::{OffsetDateTime, PrimitiveDateTime}; use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset};
use tracing::instrument; use tracing::instrument;
use wrappers::{DbHistory, DbRecord, DbSession, DbUser}; use wrappers::{DbHistory, DbRecord, DbSession, DbUser};
@ -215,8 +215,8 @@ impl Database for Postgres {
) )
.bind(user.id) .bind(user.id)
.bind(host) .bind(host)
.bind(created_after) .bind(into_utc(created_after))
.bind(since) .bind(into_utc(since))
.bind(page_size) .bind(page_size)
.fetch(&self.pool) .fetch(&self.pool)
.map_ok(|DbHistory(h)| h) .map_ok(|DbHistory(h)| h)
@ -450,3 +450,30 @@ impl Database for Postgres {
Ok(res) 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);
}
}

View file

@ -2,6 +2,7 @@ use ::sqlx::{FromRow, Result};
use atuin_common::record::{EncryptedData, Record}; use atuin_common::record::{EncryptedData, Record};
use atuin_server_database::models::{History, Session, User}; use atuin_server_database::models::{History, Session, User};
use sqlx::{postgres::PgRow, Row}; use sqlx::{postgres::PgRow, Row};
use time::PrimitiveDateTime;
pub struct DbUser(pub User); pub struct DbUser(pub User);
pub struct DbSession(pub Session); pub struct DbSession(pub Session);
@ -36,9 +37,13 @@ impl<'a> ::sqlx::FromRow<'a, PgRow> for DbHistory {
client_id: row.try_get("client_id")?, client_id: row.try_get("client_id")?,
user_id: row.try_get("user_id")?, user_id: row.try_get("user_id")?,
hostname: row.try_get("hostname")?, hostname: row.try_get("hostname")?,
timestamp: row.try_get("timestamp")?, timestamp: row
.try_get::<PrimitiveDateTime, _>("timestamp")?
.assume_utc(),
data: row.try_get("data")?, data: row.try_get("data")?,
created_at: row.try_get("created_at")?, created_at: row
.try_get::<PrimitiveDateTime, _>("created_at")?
.assume_utc(),
})) }))
} }
} }

View file

@ -37,7 +37,8 @@ rustPlatform.buildRustPackage {
# Additional flags passed to the cargo test binary, see `cargo test -- --help` # Additional flags passed to the cargo test binary, see `cargo test -- --help`
checkFlags = [ checkFlags = [
# Registration tests require a postgres server # Sync tests require a postgres server
"--skip=sync"
"--skip=registration" "--skip=registration"
]; ];

View file

@ -1,10 +1,11 @@
use std::{env, net::TcpListener, time::Duration}; use std::{env, net::TcpListener, time::Duration};
use atuin_client::api_client; 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::{launch_with_listener, Settings as ServerSettings};
use atuin_server_postgres::{Postgres, PostgresSettings}; use atuin_server_postgres::{Postgres, PostgresSettings};
use futures_util::TryFutureExt; use futures_util::TryFutureExt;
use time::OffsetDateTime;
use tokio::{sync::oneshot, task::JoinHandle}; use tokio::{sync::oneshot, task::JoinHandle};
use tracing::{dispatcher, Dispatch}; use tracing::{dispatcher, Dispatch};
use tracing_subscriber::{layer::SubscriberExt, EnvFilter}; 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() let dispatch: Dispatch = tracing_subscriber::registry()
.with(formatting_layer) .with(formatting_layer)
.with(EnvFilter::new("atuin_server=debug,info")) .with(EnvFilter::new("atuin_server=debug,atuin_client=debug,info"))
.into(); .into();
let db_uri = env::var("ATUIN_DB_URI") 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) (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] #[tokio::test]
async fn registration() { async fn registration() {
let path = format!("/{}", uuid_v7().as_simple()); let path = format!("/{}", uuid_v7().as_simple());
let (address, shutdown, server) = start_server(&path).await; let (address, shutdown, server) = start_server(&path).await;
dbg!(&address); dbg!(&address);
// -- REGISTRATION --
let username = uuid_v7().as_simple().to_string(); 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 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();
let client = api_client::Client::new(&address, &registration_response.session, 5, 30).unwrap();
// the session token works // the session token works
let status = client.status().await.unwrap(); let status = client.status().await.unwrap();
assert_eq!(status.username, username); assert_eq!(status.username, username);
// login works // -- LOGIN --
let login_response = api_client::login(
&address,
atuin_common::api::LoginRequest { username, password },
)
.await
.unwrap();
// currently we return the same session token let client = login(&address, username.clone(), password).await;
assert_eq!(registration_response.session, login_response.session);
// the session token works
let status = client.status().await.unwrap();
assert_eq!(status.username, username);
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();
assert_eq!(history.history, vec![data1, data2]);
shutdown.send(()).unwrap(); shutdown.send(()).unwrap();
server.await.unwrap(); server.await.unwrap();