mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00

This avoids a vulnerability in tokio (#3085). The major version updates of both actix-web and actix-rt required some signficant changes. Chief among those, it turns out we were relying on actix-rt to run the HttpServer in a different thread from the rest of the test, so that we could talk to it from sync code in the test thread. This no longer works, so the sync code is now run in a dedicated thread with `actix_rt::task::spawn_blocking`.
97 lines
3.3 KiB
Rust
97 lines
3.3 KiB
Rust
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<()> {
|
|
async fn server() -> anyhow::Result<u16> {
|
|
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();
|
|
actix_rt::spawn(httpserver.run());
|
|
Ok(port)
|
|
}
|
|
|
|
fn client(port: u16) -> 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 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);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
let port = server().await?;
|
|
actix_rt::task::spawn_blocking(move || client(port)).await??;
|
|
Ok(())
|
|
}
|