package xfer
import "testing"
// The forge's own checks stand between a proved caller and the child,
// whatever the child would do: each is exercised with a child that would
// accept anything, because judgeAdoption never reaches one.
func TestJudgeAdoptionOrderAndRefusals(t *testing.T) {
const code = "0123456789abcdef0123456789abcdef01234567"
type calls struct{ empty, claim, adopted int }
mk := func(c *calls, empty bool, claim Claim, recorded string, heals bool) *Fronter {
held := "old"
f := New()
f.SetAdoption(&Adoption{
Code: func(string) (string, bool) { return held, true },
Empty: func(string) bool { c.empty++; return empty },
Recorded: func(string) string { return recorded },
Claim: func(string, string) Claim { c.claim++; return claim },
Adopted: func(string) bool {
c.adopted++
if heals {
held = code
}
return heals
},
})
return f
}
var c calls
if v := mk(&c, false, ClaimOK, "", false).judgeAdoption("r", code); v.admit || v.refusal != "" || c.claim != 0 {
t.Errorf("FAIL: a repository the forge does not see as empty was judged %+v after %d claims", v, c.claim)
}
c = calls{}
if v := mk(&c, true, ClaimOK, "", false).judgeAdoption("r", code); !v.admit || !v.claimed || c.claim != 1 {
t.Errorf("FAIL: an empty, unclaimed repository was judged %+v", v)
}
c = calls{}
taken := mk(&c, true, ClaimTaken, "", false).judgeAdoption("r", code)
c = calls{}
unsure := mk(&c, true, ClaimUnsure, "", false).judgeAdoption("r", code)
if taken.admit || unsure.admit || taken.refusal == "" || unsure.refusal == "" || taken.refusal == unsure.refusal {
t.Errorf("FAIL: a taken code was %+v and an unprovable one %+v", taken, unsure)
}
// The row records this code and the caches are behind: heal, no claim.
c = calls{}
if v := mk(&c, false, ClaimOK, code, true).judgeAdoption("r", code); !v.admit || v.claimed || c.adopted != 1 || c.claim != 0 {
t.Errorf("FAIL: a stale cache was judged %+v after %d reads, %d claims", v, c.adopted, c.claim)
}
// A claim in flight is not healed from under its push.
c = calls{}
f := mk(&c, false, ClaimOK, code, true)
f.flight("r", 1)
if v := f.judgeAdoption("r", code); v.admit || c.adopted != 0 {
t.Errorf("FAIL: a row holding a live claim was healed (%+v, %d reads)", v, c.adopted)
}
f.flight("r", -1)
if v := f.judgeAdoption("r", code); !v.admit || c.adopted != 1 {
t.Errorf("FAIL: with the claim over, the row was not healed (%+v)", v)
}
// ...and when the store still cannot be read, nothing is let through
// on that account: the repository's emptiness decides, as always.
c = calls{}
if v := mk(&c, false, ClaimOK, code, false).judgeAdoption("r", code); v.admit || c.claim != 0 {
t.Errorf("FAIL: an unreadable store let a push through: %+v", v)
}
if !t.Failed() {
t.Log("ok")
}
}
// Nothing is asked of the forge about a request that names no foreign
// well-formed code, and nothing at all by cardCode.
func TestCardCodeIsAStringCheckOnly(t *testing.T) {
const held = "0123456789abcdef0123456789abcdef01234567"
asked := 0
f := New()
f.SetAuth(adoptAuthStub{})
f.SetAdoption(&Adoption{Code: func(string) (string, bool) { return held, true },
Empty: func(string) bool { asked++; return true },
Recorded: func(string) string { asked++; return "" },
Claim: func(string, string) Claim { asked++; return ClaimOK },
Adopted: func(string) bool { asked++; return true }})
foreign := "fedcba9876543210fedcba9876543210fedcba98"
for name, c := range map[string]struct {
pr pushRequest
want string
}{
"foreign": {pushRequest{hasPush: true, projectCode: foreign}, foreign},
"same": {pushRequest{hasPush: true, projectCode: held}, ""},
"no push": {pushRequest{projectCode: foreign}, ""},
"mixed": {pushRequest{hasPush: true, projectCode: foreign, codeMixed: true}, ""},
"short": {pushRequest{hasPush: true, projectCode: "abc"}, ""},
"uppercase": {pushRequest{hasPush: true, projectCode: "FEDCBA9876543210FEDCBA9876543210FEDCBA98"}, ""},
} {
if got := f.cardCode("r", c.pr); got != c.want {
t.Errorf("FAIL: %s: cardCode = %q, want %q", name, got, c.want)
}
}
if asked != 0 {
t.Errorf("FAIL: cardCode asked the forge %d questions", asked)
}
if !t.Failed() {
t.Log("ok")
}
}
type adoptAuthStub struct{ Auth }
func (adoptAuthStub) SecretsAt(repo, user, code string) []Credential { return nil }