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  }