feat: Add more swagger checks (#5707)

This commit is contained in:
Marcin Tojek 2023-01-13 16:47:38 +01:00 committed by GitHub
parent 54cc587dad
commit dad242a788
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 2 deletions

View File

@ -18,6 +18,7 @@ func TestEndpointsDocumented(t *testing.T) {
swaggerComments, err := coderdtest.ParseSwaggerComments("..")
require.NoError(t, err, "can't parse swagger comments")
require.NotEmpty(t, swaggerComments, "swagger comments must be present")
_, _, api := coderdtest.NewWithAPI(t, nil)
coderdtest.VerifySwaggerDefinitions(t, api.APIHandler, swaggerComments)

View File

@ -149,6 +149,7 @@ func parseSwaggerComment(commentGroup *ast.CommentGroup) SwaggerComment {
func VerifySwaggerDefinitions(t *testing.T, router chi.Router, swaggerComments []SwaggerComment) {
assertUniqueRoutes(t, swaggerComments)
assertSingleAnnotations(t, swaggerComments)
err := chi.Walk(router, func(method, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
method = strings.ToLower(method)
@ -192,6 +193,36 @@ func assertUniqueRoutes(t *testing.T, comments []SwaggerComment) {
}
}
var uniqueAnnotations = []string{"@ID", "@Summary", "@Tags", "@Router"}
func assertSingleAnnotations(t *testing.T, comments []SwaggerComment) {
for _, comment := range comments {
counters := map[string]int{}
for _, line := range comment.raw {
splitN := strings.SplitN(strings.TrimSpace(line.Text), " ", 3)
if len(splitN) < 2 {
continue // comment prefix without any content
}
if !strings.HasPrefix(splitN[1], "@") {
continue // not a swagger annotation
}
annotation := splitN[1]
if _, ok := counters[annotation]; !ok {
counters[annotation] = 0
}
counters[annotation]++
}
for _, annotation := range uniqueAnnotations {
v := counters[annotation]
assert.Equal(t, 1, v, "%s annotation for route %s must be defined only once", annotation, comment.router)
}
}
}
func findSwaggerCommentByMethodAndRoute(comments []SwaggerComment, method, route string) *SwaggerComment {
for _, c := range comments {
if c.method == method && c.router == route {
@ -219,6 +250,7 @@ func assertRequiredAnnotations(t *testing.T, comment SwaggerComment) {
assert.NotEmpty(t, comment.id, "@ID must be defined")
assert.NotEmpty(t, comment.summary, "@Summary must be defined")
assert.NotEmpty(t, comment.tags, "@Tags must be defined")
assert.NotEmpty(t, comment.router, "@Router must be defined")
}
func assertGoCommentFirst(t *testing.T, comment SwaggerComment) {
@ -295,6 +327,8 @@ func assertAccept(t *testing.T, comment SwaggerComment) {
}
}
var allowedProduceTypes = []string{"json", "text/event-stream"}
func assertProduce(t *testing.T, comment SwaggerComment) {
var hasResponseModel bool
for _, r := range comment.successes {
@ -306,6 +340,7 @@ func assertProduce(t *testing.T, comment SwaggerComment) {
if hasResponseModel {
assert.True(t, comment.produce != "", "Route must have @Produce annotation as it responds with a model structure")
assert.Contains(t, allowedProduceTypes, comment.produce, "@Produce value is limited to specific types: %s", strings.Join(allowedProduceTypes, ","))
} else {
if (comment.router == "/workspaceagents/me/app-health" && comment.method == "post") ||
(comment.router == "/workspaceagents/me/version" && comment.method == "post") ||

View File

@ -826,7 +826,7 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin
// @ID submit-workspace-agent-stats
// @Security CoderSessionToken
// @Accept json
// @Produce application/json
// @Produce json
// @Tags Agents
// @Param request body codersdk.AgentStats true "Stats request"
// @Success 200 {object} codersdk.AgentStatsResponse
@ -904,7 +904,7 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques
// @ID submit-workspace-agent-application-health
// @Security CoderSessionToken
// @Accept json
// @Produce application/json
// @Produce json
// @Tags Agents
// @Param request body codersdk.PostWorkspaceAppHealthsRequest true "Application health request"
// @Success 200

View File

@ -14,6 +14,7 @@ func TestEnterpriseEndpointsDocumented(t *testing.T) {
swaggerComments, err := coderdtest.ParseSwaggerComments("..", "../../../coderd")
require.NoError(t, err, "can't parse swagger comments")
require.NotEmpty(t, swaggerComments, "swagger comments must be present")
_, _, api := coderdenttest.NewWithAPI(t, nil)
coderdtest.VerifySwaggerDefinitions(t, api.AGPL.APIHandler, swaggerComments)