Skip to content

Commit

Permalink
Breaking change check: New request required default param on existing…
Browse files Browse the repository at this point in the history
… path (#376)
  • Loading branch information
Jonathan-Rosenberg authored Sep 16, 2023
1 parent 1bf3971 commit b3677f4
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 1 deletion.
1 change: 1 addition & 0 deletions BREAKING-CHANGES-EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ These examples are automatically generated from unit tests.
[modifying a pattern in a schema is breaking](checker/checker_breaking_test.go?plain=1#L491)
[modifying a pattern in request parameter is breaking](checker/checker_breaking_test.go?plain=1#L507)
[modifying the default value of an optional request parameter is breaking](checker/checker_breaking_test.go?plain=1#L537)
[new header, query and cookie required request default param is breaking](checker/check-new-request-non-path-default-parameter_test.go?plain=1#L11)
[new required header param is breaking](checker/checker_breaking_test.go?plain=1#L171)
[new required path param is breaking](checker/checker_breaking_test.go?plain=1#L155)
[new required property in request header is breaking](checker/checker_breaking_property_test.go?plain=1#L17)
Expand Down
49 changes: 49 additions & 0 deletions checker/check-new-request-non-path-default-parameter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package checker

import (
"github.com/tufin/oasdiff/diff"
)

func NewRequestNonPathDefaultParameterCheck(diffReport *diff.Diff, operationsSources *diff.OperationsSourcesMap, config Config) Changes {
result := make(Changes, 0)
if diffReport.PathsDiff == nil || len(diffReport.PathsDiff.Modified) == 0 {
return result
}
for path, pathItem := range diffReport.PathsDiff.Modified {
if pathItem.ParametersDiff == nil || pathItem.Revision == nil || len(pathItem.Revision.Operations()) == 0 {
continue
}

for paramLoc := range pathItem.ParametersDiff.Added {
if paramLoc == "path" {
continue
}

for _, param := range pathItem.Revision.Parameters {

id := "new-required-request-default-parameter-to-existing-path"
level := ERR
if !param.Value.Required {
id = "new-optional-request-default-parameter-to-existing-path"
level = INFO
}

for operation, operationItem := range pathItem.Revision.Operations() {

// TODO: if base operation had this param individually (not through the path) - continue

result = append(result, ApiChange{
Id: id,
Level: level,
Text: config.Localize(id, ColorizedValue(paramLoc), ColorizedValue(param.Value.Name)),
Operation: operation,
OperationId: operationItem.OperationID,
Path: path,
Source: (*operationsSources)[operationItem],
})
}
}
}
}
return result
}
117 changes: 117 additions & 0 deletions checker/check-new-request-non-path-default-parameter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package checker_test

import (
"testing"

"github.com/stretchr/testify/require"
"github.com/tufin/oasdiff/checker"
"github.com/tufin/oasdiff/diff"
)

// BC: new header, query and cookie required request default param is breaking
func TestNewRequestNonPathParameter_DetectsNewRequiredPathsAndNewOperations(t *testing.T) {
s1, err := open("../data/request_params/base.yaml")
require.NoError(t, err)

s2, err := open("../data/request_params/required-request-params.yaml")
require.NoError(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(&diff.Config{}, s1, s2)
require.NoError(t, err)

errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.NewRequestNonPathDefaultParameterCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Len(t, errs, 9)

require.ElementsMatch(t, []checker.ApiChange{
{
Id: "new-required-request-default-parameter-to-existing-path",
Text: "added the new required 'query' request parameter 'version' to all path's operations",
Comment: "",
Level: 3,
Operation: "GET",
OperationId: "getTest",
Path: "/api/test1",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-required-request-default-parameter-to-existing-path",
Text: "added the new required 'query' request parameter 'version' to all path's operations",
Comment: "",
Level: 3,
Operation: "POST",
OperationId: "",
Path: "/api/test1",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-required-request-default-parameter-to-existing-path",
Text: "added the new required 'header' request parameter 'id' to all path's operations",
Comment: "",
Level: 3,
Operation: "GET",
OperationId: "getTest",
Path: "/api/test2",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-required-request-default-parameter-to-existing-path",
Text: "added the new required 'query' request parameter 'id' to all path's operations",
Comment: "",
Level: 3,
Operation: "GET",
OperationId: "getTest",
Path: "/api/test2",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-required-request-default-parameter-to-existing-path",
Text: "added the new required 'header' request parameter 'If-None-Match' to all path's operations",
Comment: "",
Level: 3,
Operation: "GET",
OperationId: "getTest",
Path: "/api/test3",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-optional-request-default-parameter-to-existing-path",
Text: "added the new optional 'query' request parameter 'optionalQueryParam' to all path's operations",
Comment: "",
Level: 1,
Operation: "GET",
OperationId: "getTest",
Path: "/api/test1",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-optional-request-default-parameter-to-existing-path",
Text: "added the new optional 'query' request parameter 'optionalQueryParam' to all path's operations",
Comment: "",
Level: 1,
Operation: "POST",
OperationId: "",
Path: "/api/test1",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-optional-request-default-parameter-to-existing-path",
Text: "added the new optional 'header' request parameter 'optionalHeaderParam' to all path's operations",
Comment: "",
Level: 1,
Operation: "GET",
OperationId: "getTest",
Path: "/api/test2",
Source: "../data/request_params/required-request-params.yaml",
},
{
Id: "new-optional-request-default-parameter-to-existing-path",
Text: "added the new optional 'query' request parameter 'optionalHeaderParam' to all path's operations",
Comment: "",
Level: 1,
Operation: "GET",
OperationId: "getTest",
Path: "/api/test2",
Source: "../data/request_params/required-request-params.yaml",
}}, errs)
}
1 change: 1 addition & 0 deletions checker/default_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func defaultChecks() []BackwardCompatibilityCheck {
APISecurityUpdatedCheck,
APISunsetChangedCheck,
AddedRequiredRequestBodyCheck,
NewRequestNonPathDefaultParameterCheck,
NewRequestNonPathParameterCheck,
NewRequestPathParameterCheck,
NewRequiredRequestHeaderPropertyCheck,
Expand Down
6 changes: 5 additions & 1 deletion checker/localizations/localizations.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions checker/localizations_src/en/messages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,5 @@ request-optional-property-became-not-write-only: the request optional property %
request-optional-property-became-not-read-only: the request optional property %s became not read-only
request-required-property-became-write-only: the request required property %s became write-only
request-required-property-became-not-write-only: the request required property %s became not write-only
new-required-request-default-parameter-to-existing-path: added the new required %s request parameter %s to all path's operations
new-optional-request-default-parameter-to-existing-path: added the new optional %s request parameter %s to all path's operations
2 changes: 2 additions & 0 deletions checker/localizations_src/ru/messages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,5 @@ request-optional-property-became-not-write-only: необязательное п
request-optional-property-became-not-read-only: необязательное поле запроса %s перестало быть только для чтения
request-required-property-became-write-only: обязательное поле запроса %s стало только для записи
request-required-property-became-not-write-only: обязательное поле запроса %s перестало быть только для записи
new-required-request-default-parameter-to-existing-path: добавлен новый обязательный %s параметр запроса %s для всех операций пути
new-optional-request-default-parameter-to-existing-path: добавлен новый необязательный %s параметр запроса %s ко всем операциям пути
9 changes: 9 additions & 0 deletions data/request_params/base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,12 @@ paths:
responses:
200:
description: OK

/api/test4:
parameters:
- in: query
name: emptyPath
required: false
schema:
type: string

81 changes: 81 additions & 0 deletions data/request_params/required-request-params.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
info:
title: Tufin
version: 1.0.0
openapi: 3.0.3
paths:
/api/test1:
parameters:
- in: query
name: version
required: true
schema:
type: string
- in: query
name: optionalQueryParam
required: false
schema:
type: string
get:
operationId: getTest
parameters:
- in: header
name: X-NewRequestHeaderParam
required: false
schema:
type: string
responses:
200:
description: OK
post:
responses:
201:
description: OK

/api/test2:
parameters:
- in: query
name: id
required: true
schema:
type: string
- in: header
name: optionalHeaderParam
required: false
schema:
type: string
get:
operationId: getTest
parameters:
- in: query
name: newQueryParam
required: false
schema:
type: string
responses:
200:
description: OK

/api/test3:
parameters:
- in: header
name: If-None-Match
required: true
get:
operationId: getTest
parameters:
- in: cookie
name: csrf-token
required: false
schema:
type: string
responses:
200:
description: OK

/api/test4:
parameters:
- in: query
name: emptyPath2
required: true
schema:
type: string

0 comments on commit b3677f4

Please sign in to comment.