mirror of https://github.com/coder/coder.git
feat: Add more swagger checks (#5707)
This commit is contained in:
parent
54cc587dad
commit
dad242a788
|
@ -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)
|
||||
|
|
|
@ -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") ||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue