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)
}