github.com/oinume/lekcije@v0.0.0-20231017100347-5b4c5eb6ab24/backend/internal/twirptest/client.go (about) 1 package twirptest 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/http/httptest" 10 "testing" 11 12 "google.golang.org/protobuf/encoding/protojson" 13 "google.golang.org/protobuf/proto" 14 ) 15 16 type JSONError struct { 17 Code string `json:"code"` 18 Msg string `json:"msg"` 19 Meta map[string]string `json:"meta,omitempty"` 20 } 21 22 func (e *JSONError) Error() string { 23 return fmt.Sprintf("Code=%s, Msg=%s, Meta=%v", e.Code, e.Msg, e.Meta) 24 } 25 26 type Client interface { 27 SendRequest( 28 ctx context.Context, 29 t *testing.T, 30 handler http.Handler, 31 path string, 32 request proto.Message, 33 response proto.Message, 34 wantStatusCode int, 35 ) (int, *JSONError) 36 } 37 38 type JSONClient struct{} 39 40 func NewJSONClient() *JSONClient { 41 return &JSONClient{} 42 } 43 44 func (jc *JSONClient) SendRequest( 45 ctx context.Context, 46 t *testing.T, 47 handler http.Handler, 48 path string, 49 request proto.Message, 50 response proto.Message, 51 ) (int, error) { 52 t.Helper() 53 54 marshaler := protojson.MarshalOptions{ 55 UseProtoNames: true, 56 } 57 body, err := marshaler.Marshal(request) 58 if err != nil { 59 t.Fatalf("Marshal failed: %v", err) 60 } 61 req, err := http.NewRequest("POST", path, bytes.NewReader(body)) 62 if err != nil { 63 t.Fatalf("NewRequest failed: %v", err) 64 } 65 req.Header.Set("Content-Type", "application/json") 66 req = req.WithContext(ctx) 67 68 w := httptest.NewRecorder() 69 handler.ServeHTTP(w, req) 70 71 resp := w.Result() 72 defer resp.Body.Close() 73 if resp.StatusCode >= 300 { 74 var je JSONError 75 if err := json.NewDecoder(resp.Body).Decode(&je); err != nil { 76 t.Fatalf("Decode failed: %v", err) 77 } 78 return resp.StatusCode, &je 79 } 80 81 rawRespBody := json.RawMessage{} 82 if err := json.NewDecoder(resp.Body).Decode(&rawRespBody); err != nil { 83 t.Fatalf("Decode failed: %v", err) 84 } 85 unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} 86 if err = unmarshaler.Unmarshal(rawRespBody, response); err != nil { 87 t.Fatalf("Unmarshal failed: %v", err) 88 } 89 90 return resp.StatusCode, nil 91 }