Add a real-server smoke test
The deploy path — session open, full import, one poll — against
Fastmail, as `just smoke`. The stub shares the clients assumptions;
only the real server knows the spec, so consult it before deploying.

Assisted-by: GLM-5.3 via pi
change yxtmkwummtyloxquotouurxrsxlrusxo
commit 9c81c1b79828898db059feee9632e0a793def833
author Alpha Chen <alpha@kejadlen.dev>
date
parent rqzvxmyk
diff --git a/justfile b/justfile
index b7c7736..6bf120d 100644
--- a/justfile
+++ b/justfile
@@ -12,6 +12,12 @@ clippy:
 coverage:
     ./bin/coverage
 
+# The deploy path against real Fastmail: session open, full import,
+# one poll. Read-only; set DOCKET_SMOKE_TOKEN_FILE to a Fastmail
+# token file first.
+smoke:
+	cargo test --test smoke -- --ignored --nocapture
+
 mutants:
     #!/usr/bin/env bash
     set -uo pipefail
diff --git a/tests/smoke.rs b/tests/smoke.rs
new file mode 100644
index 0000000..38f56cf
--- /dev/null
+++ b/tests/smoke.rs
@@ -0,0 +1,35 @@
+//! The real-server smoke test: the deploy path — session open, full
+//! import, one poll — against Fastmail itself. Read-only, so a
+//! read-scope token suffices. Ignored by default; `just smoke` runs it
+//! with DOCKET_SMOKE_TOKEN_FILE naming a Fastmail token file.
+
+use camino::Utf8PathBuf;
+use docket::jmap::{Client, Credential};
+use docket::store::{Clock, Store};
+
+#[test]
+#[ignore = "run via `just smoke` with DOCKET_SMOKE_TOKEN_FILE set"]
+fn the_session_open_chain_runs_against_fastmail() -> Result<(), Box<dyn std::error::Error>> {
+    let token_file = match std::env::var("DOCKET_SMOKE_TOKEN_FILE") {
+        Ok(path) => Utf8PathBuf::from(path),
+        Err(_) => {
+            return Err("DOCKET_SMOKE_TOKEN_FILE must name a Fastmail token file".into());
+        }
+    };
+    let credential = Credential {
+        name: "smoke".into(),
+        token_file,
+    };
+    let store = Store::open_in_memory(Clock::System)?;
+    tokio::runtime::Runtime::new()?.block_on(async {
+        let client = Client::fastmail()?;
+        let mut sync = client.sync_account(&credential, &store).await?;
+        println!(
+            "session opened: email state {}, mailbox state {}",
+            sync.email_state, sync.mailbox_state
+        );
+        let counts = client.poll_once(&credential, &mut sync, &store).await?;
+        println!("poll: {counts:?}");
+        Ok(())
+    })
+}