PrintToVeraeTimeStamp/internal/veraeapi/client_test.go
Cursor Agent 48426bce0e
Send a document title as a verae-meta-git/1 history.
A non-blank document name is the first snapshot title, with restamp left false so a reprint keeps the first job. A blank name stays digest-only.
2026-10-11 05:37:25 +00:00

155 lines
5.4 KiB
Go

package veraeapi
import (
"encoding/base64"
"encoding/json"
"io"
"net/http"
"strings"
"testing"
"time"
"github.com/VeraeLLC/PrintToVeraeTimeStamp/internal/auth"
)
const digest64 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
func TestStampVeraeSendsTitleHistory(t *testing.T) {
var posted map[string]any
c := &Client{
Channel: auth.ChannelVerae,
VeraeBase: "https://api.example.test",
HTTPDo: func(req *http.Request) (*http.Response, error) {
if req.URL.Path == "/api/timestamp" {
raw, _ := io.ReadAll(req.Body)
_ = json.Unmarshal(raw, &posted)
body := `{"jobId":"job-1","certificate":"QmHist","existing":false}`
return &http.Response{StatusCode: 202, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
}
if strings.HasPrefix(req.URL.Path, "/api/status/") {
body := `{"status":"completed","result":"QmHist","completedAt":"2026-10-11T01:00:00Z"}`
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
}
if strings.HasPrefix(req.URL.Path, "/api/hash/") || req.URL.Path == "/api/verify" {
return &http.Response{StatusCode: 404, Body: io.NopCloser(strings.NewReader(`{}`)), Header: make(http.Header)}, nil
}
t.Fatalf("path %s", req.URL.Path)
return nil, nil
},
}
c.PollInterval = time.Millisecond
if _, err := c.Stamp(digest64, "Deed.pdf"); err != nil {
t.Fatal(err)
}
meta, _ := posted["metadata"].(map[string]any)
if meta["schema"] != "verae-meta-git/1" {
t.Fatalf("metadata=%v", posted["metadata"])
}
snap, _ := meta["snapshot"].(map[string]any)
if snap["title"] != "Deed.pdf" {
t.Fatalf("snapshot=%v", snap)
}
if posted["restamp"] != false {
t.Fatalf("restamp=%v", posted["restamp"])
}
}
func TestStampVeraeOmitsMetadataWithoutTitle(t *testing.T) {
var posted map[string]any
c := &Client{
Channel: auth.ChannelVerae,
VeraeBase: "https://api.example.test",
HTTPDo: func(req *http.Request) (*http.Response, error) {
if req.URL.Path == "/api/timestamp" {
raw, _ := io.ReadAll(req.Body)
_ = json.Unmarshal(raw, &posted)
body := `{"jobId":"job-1","certificate":"QmPlain","existing":false}`
return &http.Response{StatusCode: 202, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
}
if strings.HasPrefix(req.URL.Path, "/api/status/") {
body := `{"status":"completed","result":"QmPlain","completedAt":"2026-10-11T01:00:00Z"}`
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
}
if strings.HasPrefix(req.URL.Path, "/api/hash/") || req.URL.Path == "/api/verify" {
return &http.Response{StatusCode: 404, Body: io.NopCloser(strings.NewReader(`{}`)), Header: make(http.Header)}, nil
}
t.Fatalf("path %s", req.URL.Path)
return nil, nil
},
}
c.PollInterval = time.Millisecond
if _, err := c.Stamp(digest64, " "); err != nil {
t.Fatal(err)
}
if _, ok := posted["metadata"]; ok {
t.Fatalf("metadata=%v", posted["metadata"])
}
if posted["restamp"] != false {
t.Fatalf("restamp=%v", posted["restamp"])
}
}
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)
}
}