Skip to content
quarry Artifact [a911bdb164]
Login

Artifact [a911bdb164]

Artifact a911bdb164327b91ca3b6fbba0ddb589a97e21008f391d67c05819a5708d4e2f:


package api

import (
	"context"
	"errors"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/artifact"
	"craftdesign.group/quarry/internal/index"
	"craftdesign.group/quarry/internal/ops"
	"craftdesign.group/quarry/internal/timing"
)

// A mirror can carry an A card whose blob its upstream never served:
// all six attachments on tcl's ticket 5d170b5c are like that. The head
// answer "not in this store" was never remembered, so every render of
// that page asked the store six times, warm or cold. It is remembered
// until the next fold — the only way the blob can arrive — and after a
// fold the store is asked again.
func TestAMissingAttachmentIsNotAskedForAgainUntilAFold(t *testing.T) {
	ix, z, event := attachStore(t)
	ghost := strings.Repeat("d", 40)
	if err := ix.FoldNow([]index.Parsed{{Hash: strings.Repeat("a", 40), Art: &artifact.Artifact{
		Type: artifact.Attachment, Date: "2026-01-02T00:00:00", User: "dan",
		Attachment: &artifact.Attach{Name: "gone.txt", Target: event, Source: ghost},
	}}}); err != nil {
		t.Fatal(err)
	}
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Repos: NewRepos(map[string]*Repo{"test": {Index: ix, Zit: z}})}); err != nil {
		t.Fatal(err)
	}
	// head answers whether the ask reached the store.
	head := func(what string) bool {
		ctx, tm := timing.With(context.Background())
		_, err := r.Invoke(ctx, "attachment.head", attachmentHeadIn{Repo: "test", Hash: ghost})
		if !errors.Is(err, ops.ErrNotFound) {
			t.Fatalf("FAIL: %s: a blob the store lacks answered %v, want not found", what, err)
		}
		return tm.Category(timing.Zit) > 0
	}
	if !head("first ask") {
		t.Fatal("FAIL: the first ask never reached the store")
	}
	if head("second ask") {
		t.Fatal("FAIL: the second ask went back to the store for a blob it already knew was missing")
	}
	if err := ix.FoldNow([]index.Parsed{{Hash: strings.Repeat("b", 40), Art: &artifact.Artifact{
		Type: artifact.Wiki, WikiTitle: "Later", Date: "2026-01-03T00:00:00", User: "dan", Body: []byte("x\n")}}}); err != nil {
		t.Fatal(err)
	}
	if !head("after a fold") {
		t.Fatal("FAIL: after a fold the missing verdict was still served; the blob may have arrived")
	}
	t.Log("ok: a missing blob is remembered until the next fold, then asked for again")
}

// #273: zit carries no attachment content, so a Fossil mirror lacks the
// bytes of attachments its upstream never sent as artifacts. The head
// says the file is held upstream and where, with no credentials from
// the mirror's address; a repository that follows nothing still says
// not found, and so does one that follows Git, which has no attachments.
func TestAMirrorsMissingAttachmentPointsUpstream(t *testing.T) {
	ix, z, event := attachStore(t)
	ghost := strings.Repeat("e", 40)
	if err := ix.FoldNow([]index.Parsed{{Hash: strings.Repeat("c", 40), Art: &artifact.Artifact{
		Type: artifact.Attachment, Date: "2026-01-02T00:00:00", User: "dan",
		Attachment: &artifact.Attach{Name: "test.result", Target: event, Source: ghost},
	}}}); err != nil {
		t.Fatal(err)
	}
	head := func(m memMirrors) (attachmentHeadOut, error) {
		r := ops.NewRegistry()
		if err := RegisterAll(r, Deps{Version: "v", Mirrors: m, Repos: NewRepos(map[string]*Repo{"test": {Index: ix, Zit: z}})}); err != nil {
			t.Fatal(err)
		}
		out, err := r.Invoke(context.Background(), "attachment.head", attachmentHeadIn{Repo: "test", Hash: ghost})
		if err != nil {
			return attachmentHeadOut{}, err
		}
		return out.(attachmentHeadOut), nil
	}
	got, err := head(memMirrors{"test": {Repo: "test", URL: "https://anon:[email protected]/tcl/", Enabled: true}})
	if err != nil || got.Kind != attachKindMissing || got.Upstream != "https://core.tcl-lang.org/tcl/raw/"+ghost {
		t.Fatalf("FAIL: a Fossil mirror's missing file answered %+v, %v", got, err)
	}
	if _, err := head(memMirrors{}); !errors.Is(err, ops.ErrNotFound) {
		t.Errorf("FAIL: a repository that follows nothing answered %v, want not found", err)
	}
	if _, err := head(memMirrors{"test": {Repo: "test", URL: "https://github.com/x/y", Git: true, Enabled: true}}); !errors.Is(err, ops.ErrNotFound) {
		t.Errorf("FAIL: a Git mirror answered %v, want not found", err)
	}
}