rename rust/ to taskchampion/
This commit is contained in:
committed by
Tomas Babej
parent
ccb9a0fdfb
commit
12ecfa2b1e
31
taskchampion/integration-tests/tests/bindings.rs
Normal file
31
taskchampion/integration-tests/tests/bindings.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::Mutex;
|
||||
use tempfile::TempDir;
|
||||
|
||||
lazy_static! {
|
||||
// the C library running the tests is not reentrant, so we use a mutex to ensure that only one
|
||||
// test runs at a time.
|
||||
static ref MUTEX: Mutex<()> = Mutex::new(());
|
||||
}
|
||||
|
||||
macro_rules! suite(
|
||||
{ $s:ident } => {
|
||||
#[test]
|
||||
fn $s() {
|
||||
let tmp_dir = TempDir::new().expect("TempDir failed");
|
||||
let (res, output) = {
|
||||
let _guard = MUTEX.lock().unwrap();
|
||||
// run the tests in the temp dir (NOTE: this must be inside
|
||||
// the mutex guard!)
|
||||
std::env::set_current_dir(tmp_dir.as_ref()).unwrap();
|
||||
integration_tests::bindings_tests::$s()
|
||||
};
|
||||
println!("{}", output);
|
||||
if res != 0 {
|
||||
assert!(false, "test failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings_test_suites.rs"));
|
||||
90
taskchampion/integration-tests/tests/cross-sync.rs
Normal file
90
taskchampion/integration-tests/tests/cross-sync.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use actix_web::{App, HttpServer};
|
||||
use pretty_assertions::assert_eq;
|
||||
use taskchampion::{Replica, ServerConfig, Status, StorageConfig, Uuid};
|
||||
use taskchampion_sync_server::{storage::InMemoryStorage, Server};
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn cross_sync() -> anyhow::Result<()> {
|
||||
let _ = env_logger::builder()
|
||||
.is_test(true)
|
||||
.filter_level(log::LevelFilter::Trace)
|
||||
.try_init();
|
||||
|
||||
let server = Server::new(Default::default(), Box::new(InMemoryStorage::new()));
|
||||
let httpserver =
|
||||
HttpServer::new(move || App::new().configure(|sc| server.config(sc))).bind("0.0.0.0:0")?;
|
||||
|
||||
// bind was to :0, so the kernel will have selected an unused port
|
||||
let port = httpserver.addrs()[0].port();
|
||||
|
||||
httpserver.run();
|
||||
|
||||
// set up two replicas, and demonstrate replication between them
|
||||
let mut rep1 = Replica::new(StorageConfig::InMemory.into_storage()?);
|
||||
let mut rep2 = Replica::new(StorageConfig::InMemory.into_storage()?);
|
||||
|
||||
let client_key = Uuid::new_v4();
|
||||
let encryption_secret = b"abc123".to_vec();
|
||||
let make_server = || {
|
||||
ServerConfig::Remote {
|
||||
origin: format!("http://127.0.0.1:{}", port),
|
||||
client_key,
|
||||
encryption_secret: encryption_secret.clone(),
|
||||
}
|
||||
.into_server()
|
||||
};
|
||||
|
||||
let mut serv1 = make_server()?;
|
||||
let mut serv2 = make_server()?;
|
||||
|
||||
// add some tasks on rep1
|
||||
let t1 = rep1.new_task(Status::Pending, "test 1".into())?;
|
||||
let t2 = rep1.new_task(Status::Pending, "test 2".into())?;
|
||||
|
||||
// modify t1
|
||||
let mut t1 = t1.into_mut(&mut rep1);
|
||||
t1.start()?;
|
||||
let t1 = t1.into_immut();
|
||||
|
||||
rep1.sync(&mut serv1, false)?;
|
||||
rep2.sync(&mut serv2, false)?;
|
||||
|
||||
// those tasks should exist on rep2 now
|
||||
let t12 = rep2
|
||||
.get_task(t1.get_uuid())?
|
||||
.expect("expected task 1 on rep2");
|
||||
let t22 = rep2
|
||||
.get_task(t2.get_uuid())?
|
||||
.expect("expected task 2 on rep2");
|
||||
|
||||
assert_eq!(t12.get_description(), "test 1");
|
||||
assert_eq!(t12.is_active(), true);
|
||||
assert_eq!(t22.get_description(), "test 2");
|
||||
assert_eq!(t22.is_active(), false);
|
||||
|
||||
// make non-conflicting changes on the two replicas
|
||||
let mut t2 = t2.into_mut(&mut rep1);
|
||||
t2.set_status(Status::Completed)?;
|
||||
let t2 = t2.into_immut();
|
||||
|
||||
let mut t12 = t12.into_mut(&mut rep2);
|
||||
t12.set_status(Status::Completed)?;
|
||||
|
||||
// sync those changes back and forth
|
||||
rep1.sync(&mut serv1, false)?; // rep1 -> server
|
||||
rep2.sync(&mut serv2, false)?; // server -> rep2, rep2 -> server
|
||||
rep1.sync(&mut serv1, false)?; // server -> rep1
|
||||
|
||||
let t1 = rep1
|
||||
.get_task(t1.get_uuid())?
|
||||
.expect("expected task 1 on rep1");
|
||||
assert_eq!(t1.get_status(), Status::Completed);
|
||||
|
||||
let t22 = rep2
|
||||
.get_task(t2.get_uuid())?
|
||||
.expect("expected task 2 on rep2");
|
||||
assert_eq!(t22.get_status(), Status::Completed);
|
||||
|
||||
// note that we just drop the server here..
|
||||
Ok(())
|
||||
}
|
||||
94
taskchampion/integration-tests/tests/snapshots.rs
Normal file
94
taskchampion/integration-tests/tests/snapshots.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
use actix_web::{App, HttpServer};
|
||||
use pretty_assertions::assert_eq;
|
||||
use taskchampion::{Replica, ServerConfig, Status, StorageConfig, Uuid};
|
||||
use taskchampion_sync_server::{
|
||||
storage::InMemoryStorage, Server, ServerConfig as SyncServerConfig,
|
||||
};
|
||||
|
||||
const NUM_VERSIONS: u32 = 50;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn sync_with_snapshots() -> anyhow::Result<()> {
|
||||
let _ = env_logger::builder()
|
||||
.is_test(true)
|
||||
.filter_level(log::LevelFilter::Trace)
|
||||
.try_init();
|
||||
|
||||
let sync_server_config = SyncServerConfig {
|
||||
snapshot_days: 100,
|
||||
snapshot_versions: 3,
|
||||
};
|
||||
let server = Server::new(sync_server_config, Box::new(InMemoryStorage::new()));
|
||||
let httpserver =
|
||||
HttpServer::new(move || App::new().configure(|sc| server.config(sc))).bind("0.0.0.0:0")?;
|
||||
|
||||
// bind was to :0, so the kernel will have selected an unused port
|
||||
let port = httpserver.addrs()[0].port();
|
||||
|
||||
httpserver.run();
|
||||
|
||||
let client_key = Uuid::new_v4();
|
||||
let encryption_secret = b"abc123".to_vec();
|
||||
let make_server = || {
|
||||
ServerConfig::Remote {
|
||||
origin: format!("http://127.0.0.1:{}", port),
|
||||
client_key,
|
||||
encryption_secret: encryption_secret.clone(),
|
||||
}
|
||||
.into_server()
|
||||
};
|
||||
|
||||
// first we set up a single replica and sync it a lot of times, to establish a sync history.
|
||||
let mut rep1 = Replica::new(StorageConfig::InMemory.into_storage()?);
|
||||
let mut serv1 = make_server()?;
|
||||
|
||||
let mut t1 = rep1.new_task(Status::Pending, "test 1".into())?;
|
||||
log::info!("Applying modifications on replica 1");
|
||||
for i in 0..=NUM_VERSIONS {
|
||||
let mut t1m = t1.into_mut(&mut rep1);
|
||||
t1m.start()?;
|
||||
t1m.stop()?;
|
||||
t1m.set_description(format!("revision {}", i))?;
|
||||
t1 = t1m.into_immut();
|
||||
|
||||
rep1.sync(&mut serv1, false)?;
|
||||
}
|
||||
|
||||
// now set up a second replica and sync it; it should catch up on that history, using a
|
||||
// snapshot. Note that we can't verify that it used a snapshot, because the server currently
|
||||
// keeps all versions (so rep2 could sync from the beginning of the version history). You can
|
||||
// manually verify that it is applying a snapshot by adding `assert!(false)` below and skimming
|
||||
// the logs.
|
||||
|
||||
let mut rep2 = Replica::new(StorageConfig::InMemory.into_storage()?);
|
||||
let mut serv2 = make_server()?;
|
||||
|
||||
log::info!("Syncing replica 2");
|
||||
rep2.sync(&mut serv2, false)?;
|
||||
|
||||
// those tasks should exist on rep2 now
|
||||
let t12 = rep2
|
||||
.get_task(t1.get_uuid())?
|
||||
.expect("expected task 1 on rep2");
|
||||
|
||||
assert_eq!(t12.get_description(), format!("revision {}", NUM_VERSIONS));
|
||||
assert_eq!(t12.is_active(), false);
|
||||
|
||||
// sync that back to replica 1
|
||||
t12.into_mut(&mut rep2)
|
||||
.set_description("sync-back".to_owned())?;
|
||||
rep2.sync(&mut serv2, false)?;
|
||||
rep1.sync(&mut serv1, false)?;
|
||||
|
||||
let t11 = rep1
|
||||
.get_task(t1.get_uuid())?
|
||||
.expect("expected task 1 on rep1");
|
||||
|
||||
assert_eq!(t11.get_description(), "sync-back");
|
||||
|
||||
// uncomment this to force a failure and see the logs
|
||||
// assert!(false);
|
||||
|
||||
// note that we just drop the server here..
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
use taskchampion::chrono::{TimeZone, Utc};
|
||||
use taskchampion::{Replica, ServerConfig, Status, StorageConfig};
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn update_and_delete_sync_delete_first() -> anyhow::Result<()> {
|
||||
update_and_delete_sync(true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_and_delete_sync_update_first() -> anyhow::Result<()> {
|
||||
update_and_delete_sync(false)
|
||||
}
|
||||
|
||||
/// Test what happens when an update is sync'd into a repo after a task is deleted.
|
||||
/// If delete_first, then the deletion is sync'd to the server first; otherwise
|
||||
/// the update is sync'd first. Either way, the task is gone.
|
||||
fn update_and_delete_sync(delete_first: bool) -> anyhow::Result<()> {
|
||||
// set up two replicas, and demonstrate replication between them
|
||||
let mut rep1 = Replica::new(StorageConfig::InMemory.into_storage()?);
|
||||
let mut rep2 = Replica::new(StorageConfig::InMemory.into_storage()?);
|
||||
|
||||
let tmp_dir = TempDir::new().expect("TempDir failed");
|
||||
let mut server = ServerConfig::Local {
|
||||
server_dir: tmp_dir.path().to_path_buf(),
|
||||
}
|
||||
.into_server()?;
|
||||
|
||||
// add a task on rep1, and sync it to rep2
|
||||
let t = rep1.new_task(Status::Pending, "test task".into())?;
|
||||
let u = t.get_uuid();
|
||||
|
||||
rep1.sync(&mut server, false)?;
|
||||
rep2.sync(&mut server, false)?;
|
||||
|
||||
// mark the task as deleted, long in the past, on rep2
|
||||
{
|
||||
let mut t = rep2.get_task(u)?.unwrap().into_mut(&mut rep2);
|
||||
t.delete()?;
|
||||
t.set_modified(Utc.ymd(1980, 1, 1).and_hms(0, 0, 0))?;
|
||||
}
|
||||
|
||||
// sync it back to rep1
|
||||
rep2.sync(&mut server, false)?;
|
||||
rep1.sync(&mut server, false)?;
|
||||
|
||||
// expire the task on rep1 and check that it is gone locally
|
||||
rep1.expire_tasks()?;
|
||||
assert!(rep1.get_task(u)?.is_none());
|
||||
|
||||
// modify the task on rep2
|
||||
{
|
||||
let mut t = rep2.get_task(u)?.unwrap().into_mut(&mut rep2);
|
||||
t.set_description("modified".to_string())?;
|
||||
}
|
||||
|
||||
// sync back and forth
|
||||
if delete_first {
|
||||
rep1.sync(&mut server, false)?;
|
||||
}
|
||||
rep2.sync(&mut server, false)?;
|
||||
rep1.sync(&mut server, false)?;
|
||||
if !delete_first {
|
||||
rep2.sync(&mut server, false)?;
|
||||
}
|
||||
|
||||
// check that the task is gone on both replicas
|
||||
assert!(rep1.get_task(u)?.is_none());
|
||||
assert!(rep2.get_task(u)?.is_none());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user