Skip to content
quarry Artifact [13cfdf9c56]
Login

Artifact [13cfdf9c56]

Artifact 13cfdf9c566aec585fcd0b0bc5474262ef0585424a90fe8c92e3e85cdc0c9ac7:


package api

import (
	"context"
	"craftdesign.group/quarry/internal/oltp"
	"strings"
	"testing"

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

// A grant tells its SUBJECT, transactionally, never the person who
// made the change. RFC 0005's account.caps only exists to be raised at
// exactly this moment (register.go's account.grant/.revoke).
func TestAccessChangedMailsTheSubjectNotTheActor(t *testing.T) {
	accts := newFakeAccounts()
	accts.accounts["dan"] = Account{Name: "dan", Admin: true}
	accts.accounts["eve"] = Account{Name: "eve", Email: "[email protected]"}
	mail := &fakeMail{}
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Accounts: accts, Mail: mail,
		Repos: NewRepos(map[string]*Repo{"quarry": {}})}); err != nil {
		t.Fatal(err)
	}
	ctx := ops.WithUser(context.Background(), "dan")
	if _, err := r.Invoke(ctx, "account.grant", accountGrantIn{Name: "eve", Repo: "quarry", Role: "developer"}); err != nil {
		t.Fatal(err)
	}
	if !mail.to("[email protected]") {
		t.Fatalf("the subject was not mailed: %+v", mail.sent)
	}
	if len(mail.sent) != 1 {
		t.Fatalf("expected exactly one message, got %+v", mail.sent)
	}
	// A revoke tells the same way, and a re-grant of the SAME role
	// (nothing actually changed) tells nobody.
	if _, err := r.Invoke(ctx, "account.grant", accountGrantIn{Name: "eve", Repo: "quarry", Role: "developer"}); err != nil {
		t.Fatal(err)
	}
	if len(mail.sent) != 1 {
		t.Fatalf("a no-op re-grant sent mail: %+v", mail.sent)
	}
	if _, err := r.Invoke(ctx, "account.revoke", accountRevokeIn{Name: "eve", Repo: "quarry"}); err != nil {
		t.Fatal(err)
	}
	if len(mail.sent) != 2 || mail.sent[1].To != "[email protected]" {
		t.Fatalf("revoke did not mail the subject: %+v", mail.sent)
	}
}

// Granting yourself something (repo.add's owner grant) must not mail
// you about your own action.
func TestAccessChangedSilentWhenActorIsSubject(t *testing.T) {
	accts := newFakeAccounts()
	accts.accounts["dan"] = Account{Name: "dan", Email: "[email protected]"}
	mail := &fakeMail{}
	d := Deps{Accounts: accts, Mail: mail}
	d.AccessChanged(context.Background(), "dan", "dan", "quarry", "", "admin")
	if len(mail.sent) != 0 {
		t.Fatalf("an account was mailed about its own action: %+v", mail.sent)
	}
}

// With no mail plane, AccessChanged still runs its other effects (it
// must not panic or error) and simply sends nothing.
func TestAccessChangedWithNoMailPlaneSendsNothing(t *testing.T) {
	accts := newFakeAccounts()
	accts.accounts["eve"] = Account{Name: "eve", Email: "[email protected]"}
	d := Deps{Accounts: accts} // no Mail
	d.AccessChanged(context.Background(), "dan", "eve", "quarry", "", "developer")
	// Nothing to assert beyond "did not panic" — there is no mail log
	// to check, which is exactly the point: a forge with no mail
	// provider configured for this Deps sends nothing, silently.
}

// A team tells its members when they are added, removed, or their role
// changes: one email each, as the team (its name in the header, an Open
// button to its page), never for one's own action, and a change to only
// the listing is not announced.
func TestTeamMailsAreTheTeamsToTheMember(t *testing.T) {
	accts := newFakeAccounts()
	accts.accounts["eve"] = Account{Name: "eve", Email: "[email protected]"}
	mail := &fakeMail{}
	d := Deps{Origin: "https://forge.example", Accounts: accts, Mail: mail}
	ctx := context.Background()
	d.TeamMembership(ctx, "dan", "eve", "crew")
	d.TeamRoleChanged(ctx, "dan", "eve", "crew", oltp.TeamMember{Owner: false, Caps: "r", Listed: true}, oltp.TeamMember{Owner: true, Caps: "r", Listed: true})
	d.TeamRoleChanged(ctx, "dan", "eve", "crew", oltp.TeamMember{Caps: "r", Listed: true}, oltp.TeamMember{Caps: "rw", Listed: true})
	d.TeamRoleChanged(ctx, "dan", "eve", "crew", oltp.TeamMember{Caps: "r", Listed: true}, oltp.TeamMember{Caps: "r", Listed: false}) // listing only
	d.TeamRemoval(ctx, "dan", "eve", "crew")
	d.TeamMembership(ctx, "eve", "eve", "crew") // her own action
	if len(mail.sent) != 4 {
		t.Fatalf("%d mails, want added, two role changes and removed", len(mail.sent))
	}
	for _, m := range mail.sent {
		if m.To != "[email protected]" {
			t.Errorf("sent to %s", m.To)
		}
		head := m.HTML[strings.Index(m.HTML, "<body"):strings.Index(m.HTML, `<div class="q-text" style="font-size:15px;`)]
		if !strings.Contains(head, ">crew<") || strings.Contains(head, ">QUARRY<") || !strings.Contains(m.HTML, `href="https://forge.example/t/crew"`) ||
			!strings.Contains(m.HTML[strings.Index(m.HTML, `class="q-rule q-muted"`):], ">QUARRY<") {
			t.Errorf("not the team's card: %s", m.Subject)
		}
	}
}