Skip to content
quarry Artifact [5fd45d6076]
Login

Artifact [5fd45d6076]

Artifact 5fd45d6076f00f728a345db78b4aca8bcab79d25cd130dd161e9a84dfcda52dc:


package api

import (
	"context"
	"testing"

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

type recordedActs struct{ acts []oltp.ForgeAct }

// witness runs the observer the way the registry does around a command
// that succeeds: asked before the act, and told after it.
func witness(d Deps, ctx context.Context, op string, in any) {
	if after := d.WitnessOperator()(ctx, op, in); after != nil {
		after()
	}
}

func (r *recordedActs) RecordForgeAct(actor, op, repo, owner string) error {
	r.acts = append(r.acts, oltp.ForgeAct{Actor: actor, Op: op, Repo: repo, Owner: owner})
	return nil
}
func (r *recordedActs) ForgeActs(repo string, limit int) ([]oltp.ForgeAct, error) {
	var out []oltp.ForgeAct
	for _, a := range r.acts {
		if a.Repo == repo {
			out = append(out, a)
		}
	}
	return out, nil
}

// The operator's power over a repository they do not hold stays, and
// stops being invisible to the person whose repository it is.
func TestTheOperatorLeavesAReceipt(t *testing.T) {
	for _, tc := range []struct {
		name, actor, repo string
		want              bool
		why               string
	}{
		{"an operator reaching into somebody's repository", "root", "held", true,
			"this is the case the journal exists for"},
		{"the owner acting on their own", "ada", "held", false,
			"nobody needs a receipt for what they did to their own repository"},
		{"an ordinary member within their letters", "grace", "held", false,
			"a member acting is not the operator reaching in"},
		{"an operator on a store nobody holds", "root", "unclaimed", false,
			"administering the forge is the job, not an intrusion"},
	} {
		acts := &recordedActs{}
		d := Deps{
			Acts:     acts,
			Owners:   deedOwners{owner: map[string]string{"held": "ada", "unclaimed": ""}},
			Accounts: deedAccounts{admin: "root"},
		}
		witness(d, ops.WithUser(context.Background(), tc.actor),
			"repo.update", repoUpdateIn{Name: tc.repo})
		got := len(acts.acts) == 1
		if got != tc.want {
			t.Errorf("FAIL: %s: recorded=%v, want %v — %s", tc.name, got, tc.want, tc.why)
			continue
		}
		if tc.want {
			a := acts.acts[0]
			if a.Actor != tc.actor || a.Repo != tc.repo || a.Owner != "ada" || a.Op != "repo.update" {
				t.Errorf("FAIL: %s: receipt = %+v", tc.name, a)
				continue
			}
		}
		t.Logf("ok: %s", tc.name)
	}
}

// The owner AT THE TIME is recorded, not looked up later: a repository
// changes hands, and a receipt that re-resolved the owner would quietly
// re-attribute what was done to somebody who was not there.
func TestTheReceiptNamesTheOwnerAtTheTime(t *testing.T) {
	acts := &recordedActs{}
	owners := deedOwners{owner: map[string]string{"held": "ada"}}
	d := Deps{Acts: acts, Owners: owners, Accounts: deedAccounts{admin: "root"}}
	witness(d, ops.WithUser(context.Background(), "root"), "repo.update", repoUpdateIn{Name: "held"})
	owners.owner["held"] = "heir"
	got, err := acts.ForgeActs("held", 10)
	if err != nil {
		t.Fatal(err)
	}
	if len(got) != 1 || got[0].Owner != "ada" {
		t.Fatalf("receipt = %+v, want the owner at the time (ada)", got)
	}
	t.Log("ok: the receipt names who held it then")
}

// A journal that cannot be written must not fail the act it describes.
func TestAFailedReceiptDoesNotFailTheAct(t *testing.T) {
	d := Deps{Acts: nil, Owners: deedOwners{owner: map[string]string{"held": "ada"}},
		Accounts: deedAccounts{admin: "root"}}
	witness(d, ops.WithUser(context.Background(), "root"), "repo.update", repoUpdateIn{Name: "held"})
	t.Log("ok: no journal, no panic, no refusal")
}

// The owner is read BEFORE the act. A transfer changes the owner itself,
// so a witness that looked after it named the recipient as the person
// reached into (#318); a delete purges the row it would look in.
func TestTheReceiptNamesTheOwnerBeforeTheAct(t *testing.T) {
	acts := &recordedActs{}
	owners := deedOwners{owner: map[string]string{"held": "ada"}}
	d := Deps{Acts: acts, Owners: owners, Accounts: deedAccounts{admin: "root"}}
	after := d.WitnessOperator()(ops.WithUser(context.Background(), "root"), "repo.claim", repoClaimIn{Repo: "held"})
	owners.owner["held"] = "heir"
	if after == nil {
		t.Fatal("FAIL: the witness had nothing to record for an operator act")
	}
	after()
	if len(acts.acts) != 1 || acts.acts[0].Owner != "ada" {
		t.Fatalf("FAIL: receipt = %+v, want the owner before the act (ada)", acts.acts)
	}
}