File size: 3,821 Bytes
d6f631f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package server

import (
	"bytes"
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/go-chi/chi/v5"
	"github.com/stretchr/testify/require"

	"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
	"github.com/openmeterio/openmeter/pkg/framework/transport/httptransport"
	"github.com/openmeterio/openmeter/pkg/models"
)

const ErrCodeSomething models.ErrorCode = "something"

func TestIssueIfHTTPStatusKnownErrorResponses(t *testing.T) {
	t.Run("Should map http.StatusBadRequest to errors", func(t *testing.T) {
		testHandler := httptransport.NewHandler(
			func(ctx context.Context, r *http.Request) (any, error) {
				return nil, nil
			},
			func(ctx context.Context, req any) (any, error) {
				// We'll just return a validation issue to see it get mapped
				return nil, models.NewValidationIssue(ErrCodeSomething, "something went wrong", commonhttp.WithHTTPStatusCodeAttribute(http.StatusBadRequest), models.WithAttribute("expectedKey", "expectedValue"))
			},
			commonhttp.JSONResponseEncoderWithStatus[any](http.StatusOK),
		)

		r := chi.NewRouter()
		r.Handle("/", testHandler)

		req := httptest.NewRequest(http.MethodGet, "/", bytes.NewReader(nil))

		// Make request
		writer := httptest.NewRecorder()
		r.ServeHTTP(writer, req)
		res := writer.Result()

		defer res.Body.Close()

		// status
		require.Equal(t, http.StatusBadRequest, res.StatusCode, writer.Body.String())

		// Let's parse the body to json
		var body map[string]interface{}
		err := json.Unmarshal(writer.Body.Bytes(), &body)
		require.NoError(t, err)

		// extensions
		extensions, ok := body["extensions"].(map[string]interface{})
		require.True(t, ok)

		issues, ok := extensions["validationErrors"].([]interface{})
		require.True(t, ok, "got body: %+v", body)
		require.Len(t, issues, 1)

		require.Equal(t,
			map[string]interface{}{
				"code": "something",
				// See how this is removed
				// "commonhttp.httpAttributeKey:openmeter.http.status_code": 400.0,
				"expectedKey": "expectedValue",
				"message":     "something went wrong",
				"severity":    "critical",
			}, issues[0])
	})

	t.Run("Should map other statuses to errors", func(t *testing.T) {
		testHandler := httptransport.NewHandler(
			func(ctx context.Context, r *http.Request) (any, error) {
				return nil, nil
			},
			func(ctx context.Context, req any) (any, error) {
				// We'll just return a validation issue to see it get mapped
				return nil, models.NewValidationIssue(ErrCodeSomething, "something went wrong", commonhttp.WithHTTPStatusCodeAttribute(http.StatusConflict), models.WithAttribute("expectedKey", "expectedValue"))
			},
			commonhttp.JSONResponseEncoderWithStatus[any](http.StatusOK),
		)

		r := chi.NewRouter()
		r.Handle("/", testHandler)

		req := httptest.NewRequest(http.MethodGet, "/", bytes.NewReader(nil))

		// Make request
		writer := httptest.NewRecorder()
		r.ServeHTTP(writer, req)
		res := writer.Result()

		defer res.Body.Close()

		// status
		require.Equal(t, http.StatusConflict, res.StatusCode, writer.Body.String())

		// Let's parse the body to json
		var body map[string]interface{}
		err := json.Unmarshal(writer.Body.Bytes(), &body)
		require.NoError(t, err)

		// extensions
		extensions, ok := body["extensions"].(map[string]interface{})
		require.True(t, ok)

		_, ok = extensions["409"].([]interface{})
		require.False(t, ok)

		issues, ok := extensions["validationErrors"].([]interface{})
		require.True(t, ok, "got body: %+v", body)
		require.Len(t, issues, 1)

		require.Equal(t,
			map[string]interface{}{
				"code": "something",
				// See how this is removed
				// "commonhttp.httpAttributeKey:openmeter.http.status_code": 400.0,
				"expectedKey": "expectedValue",
				"message":     "something went wrong",
				"severity":    "critical",
			}, issues[0])
	})
}