Skip to content
quarry Artifact [b40c04fe0c]
Login

Artifact [b40c04fe0c]

Artifact b40c04fe0cb44d359220e0c6e58459c2b7112fc935d862740616049541fa6afb:


package api

import (
	"context"
	"go/ast"
	"go/parser"
	"go/token"
	"io/fs"
	"path/filepath"
	"strconv"
	"strings"
	"testing"
)

// Every email the forge itself sends goes through sendMail, which renders
// the card. A new call to Mail.Send anywhere else would ship a message
// without it, so this walks the sources and fails on one, the way the
// purge test catches a new repo-keyed table. (Notify's email steps are
// held to the card by notify's own test.)
func TestMailSendHasOneCallSite(t *testing.T) {
	var sites []string
	fset := token.NewFileSet()
	for _, root := range []string{"../../internal", "../../cmd"} {
		filepath.WalkDir(root, func(path string, e fs.DirEntry, err error) error {
			if err != nil || e.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
				return nil
			}
			f, perr := parser.ParseFile(fset, path, nil, 0)
			if perr != nil {
				t.Fatal(perr)
			}
			ast.Inspect(f, func(n ast.Node) bool {
				call, ok := n.(*ast.CallExpr)
				if !ok {
					return true
				}
				sel, ok := call.Fun.(*ast.SelectorExpr)
				if !ok || sel.Sel.Name != "Send" {
					return true
				}
				if recv, ok := sel.X.(*ast.SelectorExpr); ok && recv.Sel.Name == "Mail" {
					sites = append(sites, filepath.Base(path)+":"+fset.Position(call.Pos()).String())
				}
				return true
			})
			return nil
		})
	}
	if len(sites) != 1 || !strings.HasPrefix(sites[0], "transactional.go:") {
		t.Fatalf("Mail.Send must be called only from sendMail (transactional.go); found %v", sites)
	}
}

func TestSendMailSendsTheApplicationsCard(t *testing.T) {
	mail := &fakeMail{}
	d := Deps{Origin: "https://forge.example", Mail: mail}
	if err := d.sendMail(context.Background(), "[email protected]", accountMail{Subject: "s", Text: "plain", Body: "<p>x</p>", Open: "Go", URL: "https://forge.example/x"}); err != nil {
		t.Fatal(err)
	}
	if len(mail.sent) != 1 {
		t.Fatalf("%d sent", len(mail.sent))
	}
	h := mail.sent[0].HTML
	for _, want := range []string{`class="q-card"`, `src="https://forge.example/apple-touch-icon.png"`, ">QUARRY<", `class="q-btn"`} {
		if !strings.Contains(h, want) {
			t.Errorf("card lacks %s", want)
		}
	}
	if strings.Contains(h, ">quarry<") || strings.Contains(h, "lockup") || strings.Contains(h, "wordmark.png") {
		t.Error("lowercase quarry in an application email's header")
	}
}

// Every image address in a message carries its content hash, and a changed
// image gets a changed address: Gmail's proxy caches by URL.
func TestEmailImagesCarryTheirContentHash(t *testing.T) {
	prev := AssetVersion
	t.Cleanup(func() { AssetVersion = prev })
	d := Deps{Origin: "https://forge.example"}
	card := func() string {
		return d.card(accountMail{Subject: "s", Body: "<p>x</p>", Open: "Go", URL: "https://forge.example/x"})
	}
	AssetVersion = func(path string) string { return "v1-" + strconv.Itoa(len(path)) }
	one := card()
	for _, want := range []string{
		`src="https://forge.example/apple-touch-icon.png?v=v1-21"`,
		`src="https://forge.example/badge.png?v=v1-10"`,
		`src="https://forge.example/badge-sm.png?v=v1-13"`,
	} {
		if !strings.Contains(one, want) {
			t.Errorf("card lacks %s", want)
		}
	}
	AssetVersion = func(path string) string { return "v2-" + strconv.Itoa(len(path)) }
	if two := card(); two == one || strings.Contains(two, "v1-") {
		t.Error("changed bytes did not change the addresses")
	}
	// Icons in a rendered message, and the landing headline's, are versioned too.
	if got := d.mailLink("/icons/ticket-open.png"); got != "https://forge.example/icons/ticket-open.png?v=v2-22" {
		t.Errorf("icon link %q", got)
	}
	if got := d.mailLink("/r/a/ticket/1"); got != "https://forge.example/r/a/ticket/1" {
		t.Errorf("an ordinary link was versioned: %q", got)
	}
	head := string(d.landingContext(map[string]any{"summary": "eve accepted landing 3 x", "from": "eve", "number": 3, "state": "accepted"}))
	if !strings.Contains(head, "/icons/landing-accepted.png?v=v2-27") {
		t.Errorf("landing headline icon unversioned: %s", head)
	}
	// Absent a version (no web package linked) the address is the plain one.
	AssetVersion = nil
	if got := d.asset("/badge.png"); got != "https://forge.example/badge.png" {
		t.Errorf("%q", got)
	}
}