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.
155 lines
5.4 KiB
Go
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)
|
|
}
|
|
}
|