package httpserver import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "git.yuntuo.hk/k2safe/orbit/internal/fault" core "git.yuntuo.hk/k2safe/orbit/model" "git.yuntuo.hk/k2safe/orbit/platform/auth" "git.yuntuo.hk/k2safe/orbit/pulse/service" ) type batchAuthStore struct { service.Store authCalls int } func batchHTTPToken(t *testing.T) string { t.Helper() token, _, err := auth.Issue(core.ID(strings.Repeat("1", 32)), core.ID(strings.Repeat("2", 32))) if err != nil { t.Fatal(err) } return "Bearer " + token } func (s *batchAuthStore) AuthorizeSubmit(context.Context, auth.Token) error { s.authCalls++ return fault.Unauthorized } func TestBatchHTTPRejectsWholeMalformedEnvelopeBeforeWrites(t *testing.T) { for _, test := range []struct{ body, key, code string }{ {`{"items":[{"idempotency_key":"a","task":{}},{"idempotency_key":"b","task":{"unexpected":1}}]}`, "", "INVALID_ARGUMENT"}, {`{"items":[{"idempotency_key":"a","task":{"retry":{"MaxAttempts":1}}}]}`, "", "INVALID_ARGUMENT"}, {`{"items":[{"idempotency_key":"a","task":{"payload":{"x":1,"x":2}}}]}`, "", "INVALID_ARGUMENT"}, {`{"items":[null]}`, "", "INVALID_ARGUMENT"}, {`{"items":[{"idempotency_key":"a","task":null}]}`, "", "INVALID_ARGUMENT"}, {`{"items":[{"idempotency_key":"a","task":{}},{"idempotency_key":"a","task":{}}]}`, "", "INVALID_ARGUMENT"}, {`{"items":[]}`, "", "INVALID_ARGUMENT"}, {`{"items":[{"idempotency_key":"a","task":{}}]}`, "whole-batch", "INVALID_ARGUMENT"}, {`{"items":[{"idempotency_key":"a","task":{"payload":"` + strings.Repeat("x", 512<<10) + `"}}]}`, "", "BODY_TOO_LARGE"}, } { s := &batchAuthStore{} h := New("", nil, service.New(s)).Handler r := httptest.NewRequest("POST", "/v1/tasks:batch", strings.NewReader(test.body)) r.Header.Set("Content-Type", "application/json") r.Header.Set("Authorization", batchHTTPToken(t)) if test.key != "" { r.Header.Set("Idempotency-Key", test.key) } w := httptest.NewRecorder() h.ServeHTTP(w, r) var got struct { Error struct { Code string `json:"code"` } `json:"error"` } if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil || got.Error.Code != test.code || s.authCalls != 0 { t.Fatalf("got=%s auth=%d want=%s", w.Body.String(), s.authCalls, test.code) } } } func TestBatchHTTPAuthenticatesAllInvalidItems(t *testing.T) { s := &batchAuthStore{} r := httptest.NewRequest("POST", "/v1/tasks:batch", strings.NewReader(`{"items":[{"idempotency_key":"a","task":{}}]}`)) r.Header.Set("Content-Type", "application/json") r.Header.Set("Authorization", batchHTTPToken(t)) w := httptest.NewRecorder() New("", nil, service.New(s)).Handler.ServeHTTP(w, r) if w.Code != http.StatusUnauthorized || s.authCalls != 1 { t.Fatal(w.Body.String(), s.authCalls) } }