Skip to content
quarry Artifact [ccd08d868e]
Login

Artifact [ccd08d868e]

Artifact ccd08d868e9ee390bcbfd6558cf0dc5be16182c9c6babb98324ec27b93b1100b:


package harness

import (
	"encoding/json"
	"io"
	"net/http"
	"strconv"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/ops"
)

// A store ticket carries its number in its own history (54c5175f): one
// filed through the forge has it from its first artifact; ones that
// predate numbering are backfilled by an admin, who first sees what
// would be written; a second run finds nothing to do.
func TestAStoreTicketCarriesItsNumber(t *testing.T) {
	store := buildStore(t, "num")
	zrun(t, store, "ticket", "new", "--user", "dan", "title=older one", "status=Open")
	zrun(t, store, "ticket", "new", "--user", "dan", "title=newer one", "status=Open")
	srv := ingestAndServeAuth(t, map[string]string{"alpha": store}, t.TempDir(),
		func(repo, user, pass string, need ops.Auth) api.Decision { return api.Allowed })
	call := func(method, path, body string) map[string]any {
		t.Helper()
		req, _ := http.NewRequest(method, srv.URL+path, strings.NewReader(body))
		req.Header.Set("Content-Type", "application/json")
		req.SetBasicAuth("dan", "pw")
		resp, err := srv.Client().Do(req)
		if err != nil {
			t.Fatal(err)
		}
		defer resp.Body.Close()
		b, _ := io.ReadAll(resp.Body)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("%s %s: %d %s", method, path, resp.StatusCode, b)
		}
		var out map[string]any
		json.Unmarshal(b, &out)
		return out
	}
	dry := call("POST", "/api/v1/r/alpha/ticket/numbers/record", `{}`)
	have := dry["missing"].(float64)
	if have < 2 || dry["written"].(float64) != 0 {
		t.Fatalf("FAIL: a dry run answered %v", dry)
	}
	wrote := call("POST", "/api/v1/r/alpha/ticket/numbers/record", `{"write":true}`)
	if wrote["written"].(float64) != have {
		t.Fatalf("FAIL: the backfill answered %v", wrote)
	}
	if again := call("POST", "/api/v1/r/alpha/ticket/numbers/record", `{}`); again["missing"].(float64) != 0 {
		t.Fatalf("FAIL: after the backfill %v are still missing", again["missing"])
	}
	filed := call("POST", "/api/v1/r/alpha/ticket", `{"title":"filed after numbering"}`)
	next := int(have) + 1
	if int(filed["number"].(float64)) != next {
		t.Fatalf("FAIL: the new ticket is %v, want #%d", filed["number"], next)
	}
	got := call("GET", "/api/v1/r/alpha/ticket/"+strconv.Itoa(next), "")
	fields := map[string]string{}
	for _, f := range got["ticket"].(map[string]any)["fields"].([]any) {
		m := f.(map[string]any)
		fields[m["name"].(string)] = m["value"].(string)
	}
	if fields["number"] != strconv.Itoa(next) || fields["title"] != "filed after numbering" {
		t.Fatalf("FAIL: #%d opened %v", next, fields)
	}
	t.Logf("ok: dry run %v missing, backfill wrote them, rerun 0; the new ticket is #%d from its first artifact and opens by number", have, next)
}