mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-25 21:27:19 +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`.
98 lines
3.4 KiB
Rust
98 lines
3.4 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, 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();
|
|
|
|
async fn server() -> anyhow::Result<u16> {
|
|
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();
|
|
actix_rt::spawn(httpserver.run());
|
|
Ok(port)
|
|
}
|
|
|
|
fn client(port: u16) -> anyhow::Result<()> {
|
|
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");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
let port = server().await?;
|
|
actix_rt::task::spawn_blocking(move || client(port)).await??;
|
|
Ok(())
|
|
}
|