Skip to content

Commit

Permalink
rebuilt operation 4x response function.
Browse files Browse the repository at this point in the history
now operates according to the doctor model.
  • Loading branch information
daveshanley committed Jul 9, 2024
1 parent 4708439 commit 8237d7f
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 63 deletions.
64 changes: 28 additions & 36 deletions functions/openapi/operation_4x_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
package openapi

import (
"fmt"
"github.com/daveshanley/vacuum/model"
vacuumUtils "github.com/daveshanley/vacuum/utils"
"github.com/pb33f/libopenapi/utils"
"github.com/pb33f/doctor/model/high/base"
"gopkg.in/yaml.v3"
"strconv"
)
Expand All @@ -27,52 +26,45 @@ func (or Operation4xResponse) GetCategory() string {
}

// RunRule will execute the Operation4xResponse rule, based on supplied context and a supplied []*yaml.Node slice.
func (or Operation4xResponse) RunRule(nodes []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult {

if len(nodes) <= 0 {
return nil
}

func (or Operation4xResponse) RunRule(_ []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult {
var results []model.RuleFunctionResult

if context.Index.GetPathsNode() == nil {
if context.DrDocument == nil {
return results
}
ops := context.Index.GetPathsNode().Content

var opPath, opMethod string
for i, op := range ops {
if i%2 == 0 {
opPath = op.Value
continue
}
for m, method := range op.Content {
if m%2 == 0 {
opMethod = method.Value
continue
}
basePath := fmt.Sprintf("$.paths.%s.%s", opPath, opMethod)
_, responsesNode := utils.FindKeyNode("responses", method.Content)
for pathPairs := context.DrDocument.V3Document.Paths.PathItems.First(); pathPairs != nil; pathPairs = pathPairs.Next() {
pathItem := pathPairs.Value()

if responsesNode != nil {
// extract operations
for methodPairs := pathItem.GetOperations().First(); methodPairs != nil; methodPairs = methodPairs.Next() {
operation := methodPairs.Value()

// check if operation has a 4xx response
if operation.Value.Responses != nil {
seen := false
for k, response := range responsesNode.Content {
if k%2 != 0 {
continue
}
responseCode, _ := strconv.Atoi(response.Value)
if responseCode >= 400 && responseCode <= 499 {
seen = true
for codePairs := operation.Responses.Codes.First(); codePairs != nil; codePairs = codePairs.Next() {
code := codePairs.Key()

// convert code to int
codeVal, er := strconv.Atoi(code)
if er == nil {
if codeVal >= 400 && codeVal < 500 {
seen = true
break
}
}
}
if !seen {
results = append(results, model.RuleFunctionResult{
res := model.RuleFunctionResult{
Message: "operation must define at least one 4xx error response",
StartNode: method,
EndNode: vacuumUtils.BuildEndNode(method),
Path: basePath,
StartNode: operation.Responses.KeyNode,
EndNode: vacuumUtils.BuildEndNode(operation.Responses.KeyNode),
Path: operation.Responses.GenerateJSONPath(),
Rule: context.Rule,
})
}
results = append(results, res)
operation.Responses.AddRuleFunctionResult(base.ConvertRuleResult(&res))
}
}
}
Expand Down
78 changes: 51 additions & 27 deletions functions/openapi/operation_4x_response_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package openapi

import (
"fmt"
"github.com/daveshanley/vacuum/model"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
drModel "github.com/pb33f/doctor/model"
"github.com/pb33f/libopenapi"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"os"
"testing"
)
Expand All @@ -25,17 +25,25 @@ func TestOperation4xResponse_RunRule_Success(t *testing.T) {

sampleYaml, _ := os.ReadFile("../../model/test_files/burgershop.openapi.yaml")

var rootNode yaml.Node
mErr := yaml.Unmarshal(sampleYaml, &rootNode)
assert.NoError(t, mErr)
nodes, _ := utils.FindNodes(sampleYaml, "$")
rule := buildOpenApiTestRuleAction(GetAllOperationsJSONPath(), "xor", "responses", nil)
document, err := libopenapi.NewDocument(sampleYaml)
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}

m, _ := document.BuildV3Model()
path := "$"

drDocument := drModel.NewDrDocument(m)

rule := buildOpenApiTestRuleAction(path, "responses", "", nil)
ctx := buildOpenApiTestContext(model.CastToRuleAction(rule.Then), nil)
config := index.CreateOpenAPIIndexConfig()
ctx.Index = index.NewSpecIndexWithConfig(&rootNode, config)

ctx.Document = document
ctx.DrDocument = drDocument
ctx.Rule = &rule

def := Operation4xResponse{}
res := def.RunRule(nodes, ctx)
res := def.RunRule(nil, ctx)

assert.Len(t, res, 0)
}
Expand All @@ -44,17 +52,25 @@ func TestOperation4xResponse_RunRule_ExitEarly(t *testing.T) {

sampleYaml := []byte("hi: there")

var rootNode yaml.Node
mErr := yaml.Unmarshal(sampleYaml, &rootNode)
assert.NoError(t, mErr)
nodes, _ := utils.FindNodes(sampleYaml, "$")
rule := buildOpenApiTestRuleAction(GetAllOperationsJSONPath(), "xor", "responses", nil)
document, err := libopenapi.NewDocument(sampleYaml)
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}

m, _ := document.BuildV3Model()
path := "$"

drDocument := drModel.NewDrDocument(m)

rule := buildOpenApiTestRuleAction(path, "responses", "", nil)
ctx := buildOpenApiTestContext(model.CastToRuleAction(rule.Then), nil)
config := index.CreateOpenAPIIndexConfig()
ctx.Index = index.NewSpecIndexWithConfig(&rootNode, config)

ctx.Document = document
ctx.DrDocument = drDocument
ctx.Rule = &rule

def := Operation4xResponse{}
res := def.RunRule(nodes, ctx)
res := def.RunRule(nil, ctx)

assert.Len(t, res, 0)
}
Expand All @@ -63,17 +79,25 @@ func TestOperation4xResponse_RunRule_Fail(t *testing.T) {

sampleYaml, _ := os.ReadFile("../../model/test_files/stripe.yaml")

var rootNode yaml.Node
mErr := yaml.Unmarshal(sampleYaml, &rootNode)
assert.NoError(t, mErr)
nodes, _ := utils.FindNodes(sampleYaml, "$")
rule := buildOpenApiTestRuleAction(GetAllOperationsJSONPath(), "xor", "responses", nil)
document, err := libopenapi.NewDocument(sampleYaml)
if err != nil {
panic(fmt.Sprintf("cannot create new document: %e", err))
}

m, _ := document.BuildV3Model()
path := "$"

drDocument := drModel.NewDrDocument(m)

rule := buildOpenApiTestRuleAction(path, "responses", "", nil)
ctx := buildOpenApiTestContext(model.CastToRuleAction(rule.Then), nil)
config := index.CreateOpenAPIIndexConfig()
ctx.Index = index.NewSpecIndexWithConfig(&rootNode, config)

ctx.Document = document
ctx.DrDocument = drDocument
ctx.Rule = &rule

def := Operation4xResponse{}
res := def.RunRule(nodes, ctx)
res := def.RunRule(nil, ctx)

assert.Len(t, res, 402)
}

0 comments on commit 8237d7f

Please sign in to comment.