package xfer
import (
"net/http"
"net/http/httptest"
"testing"
)
// probe is a request carrying nothing but a User-Agent — the shape most
// of these tests want, where only the card stream is under test.
func probe(ua string) *http.Request {
req := httptest.NewRequest("POST", "/r/alpha", nil)
req.Header.Set("User-Agent", ua)
return req
}
// The protocol gives a clone an opening marker and a fetch none, so the
// two are counted differently and this pins the difference.
func TestScanClassifiesCloneAndPull(t *testing.T) {
for _, tc := range []struct {
name string
body string
wantClone bool
wantPull bool
}{
{"a clone opening", "clone 3 1\n", true, false},
// Later rounds of the SAME clone must not each count as one.
{"a later clone round", "clone 3 2\n", false, false},
{"a much later round", "clone 3 47\n", false, false},
{"a pull", "pull aaaa bbbb\n", false, true},
{"a sync carries both", "push aaaa bbbb\npull aaaa bbbb\n", false, true},
// The spec's rule is digit-only recognition of SEQNO, so these
// are not sequence one however much they look like it.
{"a padded seqno", "clone 3 01\n", false, false},
{"wrong arity", "clone 1\n", false, false},
{"no operation card", "# just a comment\n", false, false},
// Cards are classified after whitespace skipping, never by byte
// prefix — an indented card the backend honours must be seen.
{"an indented clone", " clone 3 1\n", true, false},
} {
pr := scanRequest([]byte(tc.body))
if pr.newClone != tc.wantClone {
t.Errorf("%s: newClone = %v, want %v", tc.name, pr.newClone, tc.wantClone)
}
if pr.hasPull != tc.wantPull {
t.Errorf("%s: hasPull = %v, want %v", tc.name, pr.hasPull, tc.wantPull)
}
}
}
// A clone is counted as a clone and not also as a fetch, or every clone
// would inflate both numbers.
func TestTallyPrefersCloneOverPull(t *testing.T) {
var got []string
f := New()
f.SetCounted(func(repo string, r Reader) {
kind := "fetch"
if r.Clone {
kind = "clone"
}
got = append(got, repo+":"+kind)
})
body := func(s string) { f.tally("alpha", scanRequest([]byte(s)), probe(""), nil) }
body("clone 3 1\npull aaaa bbbb\n")
body("pull aaaa bbbb\n")
body("push aaaa bbbb\n")
body("clone 3 2\n")
want := []string{"alpha:clone", "alpha:fetch"}
if len(got) != len(want) {
t.Fatalf("tallied %v, want %v", got, want)
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("tallied %v, want %v", got, want)
}
}
}
// No tally installed must cost nothing and crash nothing.
func TestTallyWithoutACounter(t *testing.T) {
New().tally("alpha", scanRequest([]byte("clone 3 1\n")), probe(""), nil)
}