main
go 99 lines 3.04 KB
Raw
1 package utils
2
3 import (
4 "bytes"
5 "encoding/json"
6 "errors"
7 "io"
8 "net/http"
9 "net/http/httptest"
10 "strings"
11 "testing"
12
13 "github.com/gosuda/portal-tunnel/v2/types"
14 )
15
16 func TestWriteAPIDataAndDecodeEnvelope(t *testing.T) {
17 t.Parallel()
18
19 rec := httptest.NewRecorder()
20 WriteAPIData(rec, http.StatusCreated, map[string]string{"status": "ok"})
21
22 if rec.Code != http.StatusCreated {
23 t.Fatalf("WriteAPIData() status = %d, want %d", rec.Code, http.StatusCreated)
24 }
25
26 var envelope types.APIEnvelope[map[string]string]
27 if err := json.NewDecoder(rec.Body).Decode(&envelope); err != nil {
28 t.Fatalf("json.Decode() error = %v", err)
29 }
30 if !envelope.OK || envelope.Data["status"] != "ok" {
31 t.Fatalf("decoded envelope = %+v, want ok envelope", envelope)
32 }
33 }
34
35 func TestDecodeAPIRequestError(t *testing.T) {
36 t.Parallel()
37
38 resp := &http.Response{
39 StatusCode: http.StatusForbidden,
40 Body: io.NopCloser(strings.NewReader(`{"ok":false,"error":{"code":"unauthorized","message":"denied"}}`)),
41 }
42
43 err := DecodeAPIRequestError(resp)
44 var apiErr *types.APIRequestError
45 if !errors.As(err, &apiErr) {
46 t.Fatalf("DecodeAPIRequestError() error = %T, want *types.APIRequestError", err)
47 }
48 if apiErr.StatusCode != http.StatusForbidden || apiErr.Code != "unauthorized" || apiErr.Message != "denied" {
49 t.Fatalf("DecodeAPIRequestError() = %+v, want status/code/message populated", apiErr)
50 }
51 }
52
53 func TestDecodeJSONRequestWritesInvalidJSONError(t *testing.T) {
54 t.Parallel()
55
56 req := httptest.NewRequest(http.MethodPost, "/api", strings.NewReader("{"))
57 rec := httptest.NewRecorder()
58
59 if _, ok := DecodeJSONRequest[map[string]string](rec, req, 1024); ok {
60 t.Fatal("DecodeJSONRequest() ok = true, want false")
61 }
62
63 if rec.Code != http.StatusBadRequest {
64 t.Fatalf("DecodeJSONRequest() status = %d, want %d", rec.Code, http.StatusBadRequest)
65 }
66
67 var envelope types.APIEnvelope[json.RawMessage]
68 if err := json.Unmarshal(rec.Body.Bytes(), &envelope); err != nil {
69 t.Fatalf("json.Unmarshal() error = %v", err)
70 }
71 if envelope.OK || envelope.Error == nil || envelope.Error.Code != types.APIErrorCodeInvalidJSON {
72 t.Fatalf("decoded envelope = %+v, want invalid_json error", envelope)
73 }
74 }
75
76 func TestDecodeJSONRequestAsWritesCustomInvalidError(t *testing.T) {
77 t.Parallel()
78
79 req := httptest.NewRequest(http.MethodPost, "/api", bytes.NewBufferString("{"))
80 rec := httptest.NewRecorder()
81 invalid := APIErrorResponse{
82 Status: http.StatusTeapot,
83 Code: "custom_invalid",
84 Message: "custom invalid request",
85 }
86
87 if _, ok := DecodeJSONRequestAs[map[string]string](rec, req, 1024, invalid); ok {
88 t.Fatal("DecodeJSONRequestAs() ok = true, want false")
89 }
90
91 var envelope types.APIEnvelope[json.RawMessage]
92 if err := json.Unmarshal(rec.Body.Bytes(), &envelope); err != nil {
93 t.Fatalf("json.Unmarshal() error = %v", err)
94 }
95 if rec.Code != http.StatusTeapot || envelope.OK || envelope.Error == nil ||
96 envelope.Error.Code != "custom_invalid" || envelope.Error.Message != "custom invalid request" {
97 t.Fatalf("DecodeJSONRequestAs() status/envelope = %d/%+v, want custom invalid error", rec.Code, envelope)
98 }
99 }