Files

113 lines
3.7 KiB
Go

package api
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/metazla/meta-core/internal/claim"
)
func newUDLTestServer(t *testing.T) *Server {
t.Helper()
return &Server{storage: newTestStorage(t)}
}
func udlGet(t *testing.T, s *Server, uid, cid, key string) UDLRecordResponse {
t.Helper()
req := httptest.NewRequest(http.MethodGet, "/api/udl/record?uid="+uid+"&cid="+cid+"&key="+key, nil)
rr := httptest.NewRecorder()
s.handleUDLRecordGet(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("GET record = %d %s", rr.Code, rr.Body)
}
var resp UDLRecordResponse
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
return resp
}
func udlPutBatch(t *testing.T, s *Server, claims ...claim.Claim) UDLPutBatchResponse {
t.Helper()
body, _ := json.Marshal(UDLPutBatchRequest{Records: claims})
req := httptest.NewRequest(http.MethodPut, "/api/udl/records", strings.NewReader(string(body)))
rr := httptest.NewRecorder()
s.handleUDLRecordsPut(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("PUT records = %d %s", rr.Code, rr.Body)
}
var resp UDLPutBatchResponse
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
return resp
}
// The facade stores and returns MMUR2 claims: public values in clear,
// private ones as ciphertext, tombstones with their ts.
func TestUDLFacadeRoundTrip(t *testing.T) {
s := newUDLTestServer(t)
me := testSigner(t, 7)
res := udlPutBatch(t, s,
signed(t, me, "self", "profile:name", "Ada Lovelace", 100),
signed(t, me, "bagcsaaa", "like", "true", 100),
signed(t, me, "bagcsaaa", "seek", []byte("ciphertext"), 100),
)
for _, r := range res.Results {
if !r.Accepted {
t.Fatalf("not accepted: %+v", r)
}
}
got := udlGet(t, s, me.UID, "self", "profile:name")
if !got.Exists || got.Claim == nil || got.Claim.Value.Text != "Ada Lovelace" || got.Claim.Verify() != nil {
t.Fatalf("profile = %+v", got)
}
if seek := udlGet(t, s, me.UID, "bagcsaaa", "seek"); seek.Claim == nil || seek.Claim.Value.Kind != claim.KindBytes {
t.Fatalf("seek = %+v", seek)
}
if miss := udlGet(t, s, me.UID, "bagcsaaa", "nope"); miss.Exists || miss.Claim != nil {
t.Fatalf("missing cell = %+v", miss)
}
// Retraction: stored, returned with its ts, no longer "exists".
udlPutBatch(t, s, signed(t, me, "bagcsaaa", "like", nil, 200))
if tomb := udlGet(t, s, me.UID, "bagcsaaa", "like"); tomb.Exists || tomb.Claim == nil || tomb.Claim.TS != 200 {
t.Fatalf("tombstone = %+v", tomb)
}
rr := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/udl/cid/self/aggregate?keys=profile:name", nil)
req = withVars(req, map[string]string{"cid": "self"})
s.handleUDLAggregate(rr, req)
if !strings.Contains(rr.Body.String(), `"sample_size":1`) {
t.Fatalf("aggregate = %s", rr.Body)
}
}
// A stale claim in a batch is reported in its slot without failing the rest.
func TestUDLRecordsPut_StaleSlotDoesNotFailTheBatch(t *testing.T) {
s := newUDLTestServer(t)
me := testSigner(t, 7)
udlPutBatch(t, s, signed(t, me, "bagcsaaa", "seen:s01e01", "true", 400))
res := udlPutBatch(t, s,
signed(t, me, "bagcsaaa", "seen:s01e01", "false", 300),
signed(t, me, "bagcsaaa", "seen:s01e02", "true", 300),
)
if res.Results[0].Accepted || res.Results[0].Status != "stale" || !res.Results[1].Accepted {
t.Fatalf("results = %+v", res.Results)
}
}
func TestUDLRecordsPut_RejectsEmptyBatch(t *testing.T) {
s := newUDLTestServer(t)
req := httptest.NewRequest(http.MethodPut, "/api/udl/records", strings.NewReader(`{"records":[]}`))
rr := httptest.NewRecorder()
s.handleUDLRecordsPut(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("empty batch = %d", rr.Code)
}
}