From 2e65d172cd83a9d1d2b359a887455869280c2991 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Sun, 24 Oct 2021 21:23:57 -0400 Subject: [PATCH] Add an integration test for snapshot syncing --- Cargo.lock | 2 + replica-server-tests/Cargo.toml | 2 + replica-server-tests/tests/cross-sync.rs | 5 ++ replica-server-tests/tests/snapshots.rs | 94 ++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 replica-server-tests/tests/snapshots.rs diff --git a/Cargo.lock b/Cargo.lock index 10f51edf9..d88bc7e6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2473,6 +2473,8 @@ dependencies = [ "actix-rt", "actix-web", "anyhow", + "env_logger 0.8.4", + "log", "pretty_assertions", "taskchampion", "taskchampion-sync-server", diff --git a/replica-server-tests/Cargo.toml b/replica-server-tests/Cargo.toml index 1dfb537ce..efe369b3c 100644 --- a/replica-server-tests/Cargo.toml +++ b/replica-server-tests/Cargo.toml @@ -17,3 +17,5 @@ actix-web = "^3.3.2" actix-rt = "^1.1.1" tempfile = "3" pretty_assertions = "1" +log = "^0.4.14" +env_logger = "^0.8.3" diff --git a/replica-server-tests/tests/cross-sync.rs b/replica-server-tests/tests/cross-sync.rs index 881a7481b..10b3317d2 100644 --- a/replica-server-tests/tests/cross-sync.rs +++ b/replica-server-tests/tests/cross-sync.rs @@ -5,6 +5,11 @@ 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")?; diff --git a/replica-server-tests/tests/snapshots.rs b/replica-server-tests/tests/snapshots.rs new file mode 100644 index 000000000..dbe889231 --- /dev/null +++ b/replica-server-tests/tests/snapshots.rs @@ -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(()) +}