test: expect signed one-time material uploads
- TestUploadTicket: HMAC under the jz.bm.upload.v1: label, expiry, malformed and foreign tickets, single use through the cache - TestSignedMaterialUploadRefusesBadTickets, TestCreateMaterialUploadNeedsCaller - TestRoutes, TestBMMCP and TestManageBucketKey expect the upload-url route, the uploads route with its two buckets and the upload tool - compile-only stubs
This commit is contained in:
34
mcp_test.go
34
mcp_test.go
@@ -3,6 +3,8 @@ package bm_test
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -57,6 +59,7 @@ var pinnedTools = []string{
|
||||
"bm_manage_create_class_session",
|
||||
"bm_manage_create_course",
|
||||
"bm_manage_create_deadline",
|
||||
"bm_manage_create_material_upload",
|
||||
"bm_manage_create_meeting",
|
||||
"bm_manage_create_reading",
|
||||
"bm_manage_delete_class_session",
|
||||
@@ -374,12 +377,13 @@ func testManageTools(t *testing.T, tools []pact.MCPTool) {
|
||||
|
||||
// manageToolCount is the number of management tools: 28 record and
|
||||
// material tools plus the material file tools.
|
||||
const manageToolCount = 30
|
||||
const manageToolCount = 31
|
||||
|
||||
// fileBodyKeys are the body keys of each material file tool, exactly.
|
||||
var fileBodyKeys = map[string]map[string]bool{
|
||||
"manage_attach_material_file": {"name": false, "mime": true, "content_base64": false},
|
||||
"manage_detach_material_file": {},
|
||||
"manage_attach_material_file": {"name": false, "mime": true, "content_base64": false},
|
||||
"manage_detach_material_file": {},
|
||||
"manage_create_material_upload": {},
|
||||
}
|
||||
|
||||
// testFileTool (D-10, D-11, D-17) checks one material file tool: its body
|
||||
@@ -414,6 +418,13 @@ func testFileTool(t *testing.T, tool pact.MCPTool, fields map[string]bool) {
|
||||
if !idPath {
|
||||
t.Errorf("%s: no id path field", tool.Name)
|
||||
}
|
||||
if tool.Name == "manage_create_material_upload" {
|
||||
for _, s := range []string{"10 minutes", "curl", "50 MB", "once"} {
|
||||
if !strings.Contains(tool.Description, s) {
|
||||
t.Errorf("%s: description does not mention %q", tool.Name, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
if tool.Name == "manage_detach_material_file" {
|
||||
if tool.Method != http.MethodDelete || (tool.Destructive != nil && !*tool.Destructive) {
|
||||
t.Errorf("%s is not destructive (method %s)", tool.Name, tool.Method)
|
||||
@@ -628,6 +639,23 @@ func TestManageBucketKey(t *testing.T) {
|
||||
if got := manage.Key(httptest.NewRequest(http.MethodGet, "/", nil)); !strings.HasPrefix(got, "jz.bm.manage.ip|") {
|
||||
t.Errorf("bare key = %q, want the IP", got)
|
||||
}
|
||||
ip, ok := buckets["jz.bm.upload-ip"]
|
||||
if !ok || ip.Max != 10 {
|
||||
t.Errorf("jz.bm.upload-ip declared %v with Max %d, want 10", ok, ip.Max)
|
||||
} else if got := ip.Key(httptest.NewRequest(http.MethodPost, "/", nil)); !strings.HasPrefix(got, "jz.bm.upload.ip|") {
|
||||
t.Errorf("upload IP key = %q", got)
|
||||
}
|
||||
ticket, ok := buckets["jz.bm.upload-ticket"]
|
||||
if !ok || ticket.Max != 3 {
|
||||
t.Errorf("jz.bm.upload-ticket declared %v with Max %d, want 3", ok, ticket.Max)
|
||||
} else {
|
||||
r := httptest.NewRequest(http.MethodPost, "/", nil)
|
||||
r.SetPathValue("ticket", "secret-ticket.mac")
|
||||
sum := sha256.Sum256([]byte("secret-ticket.mac"))
|
||||
if got, want := ticket.Key(r), "jz.bm.upload.ticket|"+hex.EncodeToString(sum[:])[:32]; got != want {
|
||||
t.Errorf("upload ticket key = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
token, ok := buckets["jz.bm.token"]
|
||||
if !ok {
|
||||
t.Fatal("jz.bm.token is not declared")
|
||||
|
||||
Reference in New Issue
Block a user