PrintToVeraeTimeStamp/cmd/verae-print/pending_test.go
George Lambert 6f8796c25e
Some checks failed
windows-msi / full-msi-unsigned (push) Has been cancelled
Open Zap Billing when PrintIt stamps fail for credits
On HTTP 402/429 (and credit/billing error bodies), hold the print job and open
https://zap.verae.ai/portal/?tab=billing so the user can reload prepaid balance.
Throttle browser opens to once per 10 minutes. Auth failures still use the
sign-in flow unchanged.
2026-10-20 01:07:39 -04:00

107 lines
3.4 KiB
Go

package main
import (
"errors"
"os"
"path/filepath"
"testing"
"github.com/VeraeLLC/PrintToVeraeTimeStamp/internal/job"
"github.com/VeraeLLC/PrintToVeraeTimeStamp/internal/veraeapi"
"github.com/VeraeLLC/PrintToVeraeTimeStamp/internal/vlog"
)
func pendingEnv(t *testing.T) string {
d := t.TempDir()
t.Setenv("VERAE_PENDING_DIR", filepath.Join(d, "pending"))
t.Setenv("VERAE_NO_NOTIFY", "1")
t.Setenv("VERAE_OPEN_ON_COMPLETE", "none")
return d
}
func TestHoldAndRetryAfterSignIn(t *testing.T) {
d := pendingEnv(t)
src := filepath.Join(d, "job.pdf")
_ = os.WriteFile(src, []byte("%PDF-1.4 x"), 0o600)
authErr := &veraeapi.HTTPError{Service: "zapier stamp", Status: 401, Body: "unauthorized"}
if !isAuthFailure(authErr) || !isAuthFailure(errNoKey) || isAuthFailure(errors.New("timeout")) {
t.Fatal("isAuthFailure")
}
m, err := holdJob(src, stampTarget{Title: "Printed 2026-10-03 192901", OutPath: filepath.Join(d, "chosen.pdf")}, "watch", authErr, true)
if err != nil {
t.Fatal(err)
}
if _, err := os.Stat(src); !os.IsNotExist(err) {
t.Fatal("source should have been moved")
}
if l := listPending(); len(l) != 1 || l[0].ID != m.ID {
t.Fatalf("list %v", l)
}
keyOK := false
stamp := func(pdf string, tg stampTarget, lj vlog.Job) (job.Result, error) {
if tg.OutPath != filepath.Join(d, "chosen.pdf") {
t.Errorf("chosen path lost on retry: %q", tg.OutPath)
}
if !keyOK {
return job.Result{}, authErr
}
return job.Result{ReceiptID: "R1", CertificatePDF: pdf}, nil
}
// cancelled prompt → job stays pending
prompts := 0
acquireKeyHook = func(string) bool { prompts++; return false }
defer func() { acquireKeyHook = nil }()
if handleAuthFailure("x", stamp) || len(listPending()) != 1 || prompts != 1 {
t.Fatalf("cancel: prompts=%d pending=%d", prompts, len(listPending()))
}
// a second prompt while one is open is suppressed (single prompt)
release, ok := promptLock()
if !ok {
t.Fatal("lock")
}
if handleAuthFailure("x", stamp) || prompts != 1 {
t.Fatalf("second prompt shown while locked (prompts=%d)", prompts)
}
release()
// successful sign-in → retried and removed
acquireKeyHook = func(string) bool { prompts++; keyOK = true; return true }
if !handleAuthFailure("x", stamp) || len(listPending()) != 0 {
t.Fatalf("after sign-in pending=%d", len(listPending()))
}
}
func TestRetryKeepsNonAuthFailures(t *testing.T) {
d := pendingEnv(t)
for _, n := range []string{"a.pdf", "b.pdf"} {
p := filepath.Join(d, n)
_ = os.WriteFile(p, []byte("%PDF"), 0o600)
if _, err := holdJob(p, stampTarget{Title: n}, "ipp", errNoKey, false); err != nil {
t.Fatal(err)
}
}
calls := 0
done, remaining, authFail := retryPending(func(pdf string, tg stampTarget, lj vlog.Job) (job.Result, error) {
calls++
if calls == 1 {
return job.Result{}, errors.New("network down")
}
return job.Result{ReceiptID: "R"}, nil
})
if done != 1 || remaining != 1 || authFail {
t.Fatalf("done=%d remaining=%d authFail=%v", done, remaining, authFail)
}
}
func TestIsBillingFailure(t *testing.T) {
pendingEnv(t)
bill := &veraeapi.HTTPError{Service: "zapier stamp", Status: 402, Body: `{"error":"payment_required"}`}
if !isBillingFailure(bill) {
t.Fatal("expected billing failure")
}
if isAuthFailure(bill) {
t.Fatal("402 must not be auth failure")
}
if isBillingFailure(&veraeapi.HTTPError{Status: 401, Body: "no"}) {
t.Fatal("401 is not billing")
}
}