-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathopenapi_quality_test.go
More file actions
107 lines (98 loc) · 3.62 KB
/
openapi_quality_test.go
File metadata and controls
107 lines (98 loc) · 3.62 KB
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
package arc
import (
"context"
"net/http"
"regexp"
"strings"
"testing"
)
func TestOpenAPIRootTagsServersAndSecuritySchemes(t *testing.T) {
type in struct{}
type out struct {
OK bool `json:"ok"`
}
e := New()
e.SetOpenAPIServers([]map[string]any{{"url": "http://localhost:8080/api/v1", "description": "dev"}})
e.RegisterOpenAPISecurityScheme("BearerAuth", map[string]any{
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
})
Handle(e, http.MethodGet, "/x", "x_get", func(ctx context.Context, in *in) (*Response[out], error) {
return OK(out{OK: true}), nil
}, WithTags("Auth"), WithSecurity("BearerAuth"))
spec := e.registry.OpenAPISpec()
raw := mustJSON(spec)
if !strings.Contains(raw, `"tags":[{"name":"Auth"}]`) {
t.Fatalf("root tags missing: %s", raw)
}
if !strings.Contains(raw, `"servers":[{"description":"dev","url":"http://localhost:8080/api/v1"}]`) {
t.Fatalf("servers missing: %s", raw)
}
if !strings.Contains(raw, `"securitySchemes":{"BearerAuth"`) {
t.Fatalf("security schemes missing: %s", raw)
}
if !strings.Contains(raw, `"application/problem+json"`) {
t.Fatalf("problem+json response missing: %s", raw)
}
}
func TestOpenAPIExamples(t *testing.T) {
type in struct {
Name string `json:"name"`
}
type out struct {
ID int64 `json:"id"`
}
e := New()
Handle(e, http.MethodPost, "/users", "users_create", func(ctx context.Context, in *in) (*Response[out], error) {
return Created(out{ID: 1}), nil
}, WithRequestExamples(map[string]any{
"valid": map[string]any{"name": "alice"},
}), WithResponseExamples(map[string]any{
"ok": map[string]any{"id": 1},
}))
spec := e.registry.OpenAPISpec()
raw := mustJSON(spec)
if !strings.Contains(raw, `"requestBody"`) || !strings.Contains(raw, `"examples":{"valid":{"value":{"name":"alice"}}}`) {
t.Fatalf("request examples missing: %s", raw)
}
if !strings.Contains(raw, `"responses"`) || !strings.Contains(raw, `"examples":{"ok":{"value":{"id":1}}}`) {
t.Fatalf("response examples missing: %s", raw)
}
}
func TestOpenAPIComponentNamesAreURIFragmentSafe(t *testing.T) {
type wrapped struct {
Data []map[string]any `json:"data"`
}
e := New()
Handle(e, http.MethodGet, "/safe", "safe_get", func(ctx context.Context, in *struct{}) (*Response[wrapped], error) {
return OK(wrapped{Data: []map[string]any{{"ok": true}}}), nil
})
raw := mustJSON(e.registry.OpenAPISpec())
if strings.Contains(raw, "#/components/schemas/") && strings.Contains(raw, "/internal/") {
t.Fatalf("unsafe component ref detected: %s", raw)
}
re := regexp.MustCompile(`"#/components/schemas/[^"]*[/\[\]]`)
if re.MatchString(raw) {
t.Fatalf("component reference contains unsafe chars: %s", raw)
}
}
func TestOpenAPIExplicitProblemResponses(t *testing.T) {
e := New()
Handle(e, http.MethodGet, "/secure", "secure_get", func(ctx context.Context, in *struct{}) (*Response[map[string]any], error) {
return OK(map[string]any{"ok": true}), nil
}, WithProblemResponseSpec(map[int]ProblemExampleSpec{
http.StatusUnauthorized: {Code: "auth_unauthorized", Detail: "missing or invalid bearer token"},
http.StatusUnprocessableEntity: {Code: "validation_error", Detail: "validation failed"},
}))
raw := mustJSON(e.registry.OpenAPISpec())
if !strings.Contains(raw, `"401":{"content":{"application/problem+json"`) {
t.Fatalf("401 problem response missing: %s", raw)
}
if !strings.Contains(raw, `"422":{"content":{"application/problem+json"`) {
t.Fatalf("422 problem response missing: %s", raw)
}
if !strings.Contains(raw, `"code":"auth_unauthorized"`) || !strings.Contains(raw, `"code":"validation_error"`) {
t.Fatalf("problem response examples missing: %s", raw)
}
}