Skip to content
quarry Artifact [399f15963a]
Login

Artifact [399f15963a]

Artifact 399f15963ade0a41f9aadd972d06a6c07f09e80f575d05911b033b48494fda0d:


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) { pr := scanRequest([]byte(s)); f.tally("alpha", pr, pr, probe("")) }
	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) {
	pr := scanRequest([]byte("clone 3 1\n"))
	New().tally("alpha", pr, pr, probe(""))
}