mod common;
use std::sync::Arc;
use common::{mint_key, principal, Plane};
use gunnar_core::model::{Grant, Visibility};
use gunnar_core::{NewRepo, RepoRef};
use gunnar_ssh::command::GitService;
use gunnar_ssh::server::Dispatch;
use gunnar_ssh::{Access, PackCeiling, PlanAction, PlanGate, PlanVerdict, ServiceRequest};
const CEILING: u64 = 64 * 1024;
const LFS_ROOM: u64 = 16 * 1024;
const REFUSAL: &str = "plan 10gb would pass its pack quota with this push";
struct Metered {
during_the_walk: u64,
}
impl PlanGate for Metered {
fn verdict(&self, _: &str, _: PlanAction) -> PlanVerdict {
PlanVerdict::Allow
}
fn pack_quota(&self, _: &str) -> PlanVerdict {
PlanVerdict::Allow
}
fn pack_ceiling(&self, namespace: &str) -> Option<PackCeiling> {
if self.during_the_walk > 0 {
let other = gunnar_lfs::AllowanceLedger::shared_pack().mark(namespace);
assert_eq!(
other.admit_upto(self.during_the_walk, u64::MAX),
self.during_the_walk,
"the fixture's own admission must have been charged"
);
}
Some(PackCeiling {
bytes: CEILING,
refusal: REFUSAL.to_owned(),
})
}
fn lfs_allowance(&self, _: &str) -> Option<gunnar_lfs::Allowance> {
Some(gunnar_lfs::Allowance {
bytes: LFS_ROOM,
refusal: "plan 10gb has no LFS room left".to_owned(),
})
}
fn name(&self) -> &'static str {
"metered"
}
}
struct Uncapped;
impl PlanGate for Uncapped {
fn verdict(&self, _: &str, _: PlanAction) -> PlanVerdict {
PlanVerdict::Allow
}
fn pack_quota(&self, _: &str) -> PlanVerdict {
PlanVerdict::Allow
}
fn name(&self) -> &'static str {
"uncapped"
}
}
fn repo(namespace: &str) -> RepoRef {
RepoRef::new(namespace, "osm-katana").expect("a legitimate path")
}
fn authorise(dispatch: &Dispatch, namespace: &str, service: GitService) -> ServiceRequest {
dispatch
.authorise_service(&principal("principal-1"), None, service, repo(namespace))
.expect("the gates allow this push")
}
fn door(namespace: &str, gate: Arc<dyn PlanGate>) -> Dispatch {
let key = mint_key();
let plane = Plane::empty()
.with_principal("principal-1")
.with_key("principal-1", &key);
plane
.catalog()
.create_namespace(namespace)
.expect("create namespace");
plane
.catalog()
.create(NewRepo::new(repo(namespace)).visibility(Visibility::Private))
.expect("create repository");
plane
.auth()
.grant(Grant::repo("principal-1", repo(namespace), Access::Write))
.expect("grant");
Dispatch::new(plane.control.with_plan_gate(gate))
}
#[test]
fn a_capped_push_carries_both_the_number_and_its_standing_in_the_ledger() {
let dispatch = door("one-push", Arc::new(Metered { during_the_walk: 0 }));
let request = authorise(&dispatch, "one-push", GitService::ReceivePack);
assert_eq!(
request.pack_ceiling.as_ref().expect("a ceiling").bytes,
CEILING,
"the gate's number must reach the transport unchanged"
);
let mark = request.pack_mark.as_ref().expect(
"a capped push with no mark is a ceiling every connection is held to separately, which \
is the defect this closed",
);
assert_eq!(
mark.namespace(),
"one-push",
"the standing must be in the pushing namespace's counter and no other"
);
}
#[test]
fn two_pushes_arriving_together_share_one_namespaces_room() {
let dispatch = door("two-pushes", Arc::new(Metered { during_the_walk: 0 }));
let first = authorise(&dispatch, "two-pushes", GitService::ReceivePack);
let second = authorise(&dispatch, "two-pushes", GitService::ReceivePack);
let first_mark = first.pack_mark.expect("a mark");
let second_mark = second.pack_mark.expect("a mark");
assert_eq!(
first_mark.admit_upto(CEILING, CEILING),
CEILING,
"the first push may spend the whole of the room that was measured for it"
);
assert_eq!(
second_mark.admit_upto(CEILING, CEILING),
0,
"the second push was admitted against room the first one is already spending: that is \
the same measurement handed out twice"
);
}
#[test]
fn the_mark_is_taken_before_the_gate_measures() {
let landed = CEILING / 2;
let dispatch = door(
"mid-walk",
Arc::new(Metered {
during_the_walk: landed,
}),
);
let request = authorise(&dispatch, "mid-walk", GitService::ReceivePack);
let mark = request.pack_mark.expect("a mark");
assert_eq!(
mark.admit_upto(CEILING, CEILING),
CEILING - landed,
"an admission that landed while the gate measured is invisible to this push: the mark \
was taken AFTER the walk, and the namespace's room has now been handed out twice"
);
}
#[test]
fn the_pack_meter_and_the_lfs_meter_are_not_the_same_counter() {
let dispatch = door("two-meters", Arc::new(Metered { during_the_walk: 0 }));
let request = authorise(&dispatch, "two-meters", GitService::ReceivePack);
let mark = request.pack_mark.expect("a mark");
assert_eq!(mark.admit_upto(CEILING, CEILING), CEILING);
request
.lfs_allowance
.expect("an LFS allowance")
.admit(LFS_ROOM)
.expect(
"a push spending the pack cap has taken the tenant's LFS room with it; they are two \
caps on the fact and two counters here",
);
}
#[test]
fn a_push_with_no_ceiling_carries_no_mark() {
let uncapped = door("uncapped", Arc::new(Uncapped));
let push = authorise(&uncapped, "uncapped", GitService::ReceivePack);
assert!(
push.pack_ceiling.is_none() && push.pack_mark.is_none(),
"an uncapped plan must carry neither a ceiling nor a standing in one"
);
let capped = door(
"no-ceiling-on-a-clone",
Arc::new(Metered { during_the_walk: 0 }),
);
let clone = authorise(&capped, "no-ceiling-on-a-clone", GitService::UploadPack);
assert!(
clone.pack_ceiling.is_none() && clone.pack_mark.is_none(),
"a clone takes no byte ceiling and must not spend a byte of the push meter"
);
}