PrintToVeraeTimeStamp/internal/veraeapi/client_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

101 lines
3.4 KiB
Go

package veraeapi
import (
"encoding/base64"
"io"
"net/http"
"strings"
"testing"
"github.com/VeraeLLC/PrintToVeraeTimeStamp/internal/auth"
)
const digest64 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
func TestStampVeraeImmediateCertificate(t *testing.T) {
c := &Client{
Channel: auth.ChannelVerae,
VeraeBase: "https://api.example.test",
VeraeToken: "tok",
HTTPDo: func(req *http.Request) (*http.Response, error) {
switch {
case req.URL.Path == "/api/timestamp":
body := `{"existing":true,"certificate":"QmTestReceipt","receipts":[{"certificate":"QmTestReceipt","digest":"` + digest64 + `","completedAt":"2026-10-03T07:03:17.669231143Z","blockIndex":"113198"}]}`
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
case strings.HasPrefix(req.URL.Path, "/api/hash/"):
body := `{"receipts":[{"certificate":"QmTestReceipt","completedAt":"2026-10-03T07:03:17.669231143Z"}]}`
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
case req.URL.Path == "/api/verify":
body := `{"valid":true,"timestamp":"2026-10-03T07:03:17.669231143Z","blockIndex":113198}`
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
default:
t.Fatalf("path %s", req.URL.Path)
return nil, nil
}
},
}
r, err := c.Stamp(digest64, "Doc.pdf")
if err != nil {
t.Fatal(err)
}
if r.ReceiptID != "QmTestReceipt" {
t.Fatalf("receipt %q", r.ReceiptID)
}
if r.CreatedAt != "2026-10-03T07:03:17.669231143Z" {
t.Fatalf("created_at %q", r.CreatedAt)
}
}
func TestStampZapierAttachPdf(t *testing.T) {
pdf := []byte("%PDF-1.4 cert")
b64 := base64.StdEncoding.EncodeToString(pdf)
c := &Client{
Channel: auth.ChannelZapier,
ZapierBase: "https://zap.example.test",
XVeraeToken: "xVerae-test",
HTTPDo: func(req *http.Request) (*http.Response, error) {
if req.URL.Path != "/v1/timestamp" {
t.Fatalf("path %s", req.URL.Path)
}
if req.Header.Get("x-api-key") != "xVerae-test" {
t.Fatal("missing x-api-key")
}
body := `{"receipt_id":"cid123","pdfBase64":"` + b64 + `","pdfFilename":"reg.pdf"}`
return &http.Response{
StatusCode: 200,
Body: io.NopCloser(strings.NewReader(body)),
Header: make(http.Header),
}, nil
},
}
r, err := c.Stamp(digest64, "Contract.pdf")
if err != nil {
t.Fatal(err)
}
if r.ReceiptID != "cid123" || string(r.PDF) != string(pdf) {
t.Fatalf("%+v", r)
}
}
func TestIsBillingError(t *testing.T) {
cases := []struct {
err error
want bool
}{
{nil, false},
{&HTTPError{Service: "zapier stamp", Status: 402, Body: `{"error":"payment_required"}`}, true},
{&HTTPError{Service: "zapier stamp", Status: 429, Body: "rate limit"}, true},
{&HTTPError{Service: "zapier stamp", Status: 403, Body: "billing_failed: no credits"}, true},
{&HTTPError{Service: "zapier stamp", Status: 500, Body: "out of credit"}, true},
{&HTTPError{Service: "zapier stamp", Status: 401, Body: "unauthorized"}, false},
{&HTTPError{Service: "zapier stamp", Status: 500, Body: "upstream timeout"}, false},
}
for _, c := range cases {
if got := IsBillingError(c.err); got != c.want {
t.Errorf("IsBillingError(%v)=%v want %v", c.err, got, c.want)
}
}
if IsAuthError(&HTTPError{Status: 402, Body: "x"}) {
t.Fatal("402 must not be auth")
}
}