PrintToVeraeTimeStamp/cmd/verae-print/pending_test.go
Grok Bot (for George) 13ebc351f5 0.3.2: Save As filename prompt per print (Windows + macOS)
- promptForFilename setting (default true; env VERAE_PROMPT_FOR_FILENAME),
  'verae-print config --prompt-for-filename', last Save As folder in
  ~/.verae/state.json
- Windows helper: common file dialog (PDF filter, overwrite prompt, topmost
  owner) before stamping; macOS printer path: choose file name (NSSavePanel)
  via 'stamp -prompt-name -title'; cancel discards the job (no stamp/credit)
- job.Options.OutPath: original saved at the chosen path, certificate and
  .verae.json next to it with the chosen base name (never overwritten)
- held jobs keep the chosen path (pendingMeta.OutPath)
- installer: 'Ask for a file name for each print' checkbox; removed the
  'Open the user guide' finish-page checkbox; mac-key-setup asks too
- auth test no longer touches the real macOS keychain (VERAE_SKIP_KEYCHAIN)
- version 0.3.2
2026-10-03 20:00:56 -04:00

93 lines
3 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)
}
}