crates/gunnar-cli/tests/last_seen_push.rs
#![cfg(feature = "http")]
//! **A push is an operation; a fetch is not** (owner, 2026-10-21: the admin's
//! user list shows when each person last did something).
//!
//! Over smart HTTP — the same `GitTransport` an SSH push goes through, so one
//! transport proves the stamp's place (`serve_receive_pack`), and this test
//! needs `git` only, not `ssh`. The gRPC half (a sign-in, a control-plane
//! change, a read, the admin's list) is `gunnar-server/tests/last_seen.rs`.
mod common;
use common::{Harness, HarnessOptions};
use gunnar_core::{HashKind, Visibility};
const NS: &str = "team";
const REPO: &str = "project";
#[test]
fn a_push_stamps_the_pusher_and_a_fetch_does_not() {
let harness = Harness::start_with_options(
NS,
REPO,
HashKind::Sha1,
HarnessOptions {
http: true,
visibility: Visibility::Private,
..HarnessOptions::default()
},
);
let token = harness.mint_token("tester");
let url = harness.http_url_with_token(NS, REPO, &token);
// A read first: it authenticates as `tester` and changes nothing.
harness
.git_http(harness.dir.path(), &["ls-remote", &url])
.expect_ok("ls-remote over http");
assert_eq!(
harness.stores.activity().seen("tester").operated,
None,
"a fetch-side call is not an operation"
);
let work = harness.dir.path().join("work");
harness
.git(
harness.dir.path(),
&[
"init",
"--quiet",
"-b",
"main",
work.to_str().expect("utf-8"),
],
)
.expect_ok("git init");
std::fs::write(work.join("a.txt"), "hello\n").expect("write");
harness.git(&work, &["add", "."]).expect_ok("add");
harness
.git(&work, &["commit", "--quiet", "-m", "hello"])
.expect_ok("commit");
let before = gunnar_core::now_ms();
harness
.git_http(&work, &["push", "--quiet", &url, "main"])
.expect_ok("push over http");
let operated = harness
.stores
.activity()
.seen("tester")
.operated
.expect("the push is an operation");
assert!(operated >= before, "{operated} < {before}");
assert_eq!(
harness.stores.activity().seen("tester").signed_in,
None,
"a push is not a sign-in"
);
}