Skip to content

Commit

Permalink
Merge pull request #66 from Tufin/required-properties
Browse files Browse the repository at this point in the history
Required properties
  • Loading branch information
Reuven Harrison authored Jan 8, 2022
2 parents 19205ad + fe4409e commit 0b9c21e
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 118 deletions.
5 changes: 5 additions & 0 deletions diff/components_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ type ComponentsDiff struct {
CallbacksDiff *CallbacksDiff `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
}

// Empty indicates whether a change was found in this element
func (diff *ComponentsDiff) Empty() bool {
return diff == nil || *diff == ComponentsDiff{}
}

func getComponentsDiff(config *Config, s1, s2 openapi3.Components) (ComponentsDiff, error) {

result := ComponentsDiff{}
Expand Down
199 changes: 161 additions & 38 deletions diff/diff_breaking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,34 @@ import (
)

func TestBreaking_Same(t *testing.T) {
require.True(t, d(t, &diff.Config{BreakingOnly: true}, 1, 1).Empty())
require.Empty(t, d(t, &diff.Config{BreakingOnly: true}, 1, 1))
}

func TestBreaking_DeletedPaths(t *testing.T) {
require.False(t, d(t, &diff.Config{BreakingOnly: true}, 1, 2).Empty())
require.NotEmpty(t, d(t, &diff.Config{BreakingOnly: true}, 1, 2))
}

func TestBreaking_DeletedTagAllChanges(t *testing.T) {
require.False(t, d(t, &diff.Config{
require.NotEmpty(t, d(t, &diff.Config{
BreakingOnly: false,
}, 1, 5).PathsDiff.Modified[securityScorePath].OperationsDiff.Modified["GET"].TagsDiff.Empty())
}, 1, 5).PathsDiff.Modified[securityScorePath].OperationsDiff.Modified["GET"].TagsDiff)
}

func TestBreaking_DeletedTag(t *testing.T) {
require.True(t, d(t, &diff.Config{
require.Empty(t, d(t, &diff.Config{
BreakingOnly: true,
}, 1, 5).PathsDiff.Modified[securityScorePath].OperationsDiff.Modified["GET"].TagsDiff.Empty())
}, 1, 5).PathsDiff.Modified[securityScorePath].OperationsDiff.Modified["GET"].TagsDiff)
}

func TestBreaking_DeletedEnum(t *testing.T) {
require.False(t,
require.NotEmpty(t,
d(t, &diff.Config{
BreakingOnly: true,
}, 3, 1).PathsDiff.Modified[installCommandPath].OperationsDiff.Modified["GET"].ParametersDiff.Modified[openapi3.ParameterInPath]["project"].SchemaDiff.EnumDiff.Empty())
}, 3, 1).PathsDiff.Modified[installCommandPath].OperationsDiff.Modified["GET"].ParametersDiff.Modified[openapi3.ParameterInPath]["project"].SchemaDiff.EnumDiff)
}

func TestBreaking_AddedEnum(t *testing.T) {
require.Nil(t,
require.Empty(t,
d(t, &diff.Config{
BreakingOnly: true,
}, 1, 3).PathsDiff.Modified[installCommandPath].OperationsDiff.Modified["GET"].ParametersDiff.Modified[openapi3.ParameterInPath])
Expand All @@ -48,23 +48,12 @@ func TestBreaking_ModifiedExtension(t *testing.T) {
IncludeExtensions: diff.StringSet{"x-extension-test2": struct{}{}},
}

require.True(t, d(t, &config, 1, 3).ExtensionsDiff.Empty())
require.Empty(t, d(t, &config, 1, 3).ExtensionsDiff)
}

func TestBreaking_Components(t *testing.T) {

dd := d(t, &diff.Config{BreakingOnly: true},
1, 3)

require.Empty(t, dd.SchemasDiff)
require.Empty(t, dd.ParametersDiff)
require.Empty(t, dd.HeadersDiff)
require.Empty(t, dd.RequestBodiesDiff)
require.Empty(t, dd.ResponsesDiff)
require.Empty(t, dd.SecuritySchemesDiff)
require.Empty(t, dd.ExamplesDiff)
require.Empty(t, dd.LinksDiff)
require.Empty(t, dd.CallbacksDiff)
require.Empty(t, d(t, &diff.Config{BreakingOnly: true},
1, 3).ComponentsDiff)
}

func TestCompareWithDefault(t *testing.T) {
Expand All @@ -79,11 +68,112 @@ func TestCompareWithDefault_Nil(t *testing.T) {
)
}

func TestBreaking_NewRequiredProperty(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: "string",
Description: "Unique ID of the course",
},
}
s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{"courseId"}

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.NotEmpty(t, d)
}

func TestBreaking_NewNonRequiredProperty(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: "string",
Description: "Unique ID of the course",
},
}

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.Empty(t, d)
}

func TestBreaking_PropertyRequiredEnabled(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

sr := openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: "string",
Description: "Unique ID of the course",
},
}

s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &sr
s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{}

s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &sr
s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{"courseId"}

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.NotEmpty(t, d)
}

func TestBreaking_PropertyRequiredDisabled(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

sr := openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: "string",
Description: "Unique ID of the course",
},
}

s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &sr
s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{"courseId"}

s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Properties["courseId"] = &sr
s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Schema.Value.Required = []string{}

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.Empty(t, d)
}

func deleteParam(op *openapi3.Operation, in string, name string) {

result := openapi3.NewParameters()

for _, item := range op.Parameters {
if v := item.Value; v != nil {
if v.Name == name && v.In == in {
continue
}
result = append(result, item)
}
}
op.Parameters = result
}

func TestBreaking_NewPathParam(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInPath, "domain").Name = ""
deleteParam(s1.Paths[installCommandPath].Get, openapi3.ParameterInPath, "project")
// note: path params are always required

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
Expand All @@ -92,14 +182,14 @@ func TestBreaking_NewPathParam(t *testing.T) {

require.Contains(t,
d.PathsDiff.Modified[installCommandPath].OperationsDiff.Modified["GET"].ParametersDiff.Added[openapi3.ParameterInPath],
"domain")
"project")
}

func TestBreaking_NewRequiredHeaderParam(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Name = ""
deleteParam(s1.Paths[installCommandPath].Get, openapi3.ParameterInHeader, "network-policies")
s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Required = true

d, err := diff.Get(&diff.Config{
Expand All @@ -112,21 +202,54 @@ func TestBreaking_NewRequiredHeaderParam(t *testing.T) {
"network-policies")
}

func TestBreaking_NewNoneRequiredHeaderParam(t *testing.T) {
func TestBreaking_NewNonRequiredHeaderParam(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Name = ""
deleteParam(s1.Paths[installCommandPath].Get, openapi3.ParameterInHeader, "network-policies")
s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Required = false

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)

require.NotContains(t,
d.PathsDiff.Modified[installCommandPath].OperationsDiff.Modified["GET"].ParametersDiff.Added[openapi3.ParameterInPath],
"network-policies")
require.Empty(t, d)
}

func TestBreaking_HeaderParamRequiredEnabled(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Required = false
s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Required = true

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)

require.Equal(t,
&diff.ValueDiff{
From: false,
To: true,
},
d.PathsDiff.Modified[installCommandPath].OperationsDiff.Modified["GET"].ParametersDiff.Modified[openapi3.ParameterInHeader]["network-policies"].RequiredDiff)
}

func TestBreaking_HeaderParamRequiredDisabled(t *testing.T) {
s1 := l(t, 1)
s2 := l(t, 1)

s1.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Required = true
s2.Paths[installCommandPath].Get.Parameters.GetByInAndName(openapi3.ParameterInHeader, "network-policies").Required = false

d, err := diff.Get(&diff.Config{
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)

require.Empty(t, d)
}

func TestBreaking_MaxLengthSmaller(t *testing.T) {
Expand All @@ -143,7 +266,7 @@ func TestBreaking_MaxLengthSmaller(t *testing.T) {
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.False(t, d.Empty())
require.NotEmpty(t, d)
}

func TestBreaking_MaxLengthGreater(t *testing.T) {
Expand All @@ -160,7 +283,7 @@ func TestBreaking_MaxLengthGreater(t *testing.T) {
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.True(t, d.Empty())
require.Empty(t, d)
}

func TestBreaking_MaxLengthFromNil(t *testing.T) {
Expand All @@ -176,7 +299,7 @@ func TestBreaking_MaxLengthFromNil(t *testing.T) {
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.False(t, d.Empty())
require.NotEmpty(t, d)
}

func TestBreaking_MaxLengthToNil(t *testing.T) {
Expand All @@ -192,7 +315,7 @@ func TestBreaking_MaxLengthToNil(t *testing.T) {
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.True(t, d.Empty())
require.Empty(t, d)
}

func TestBreaking_MaxLengthBothNil(t *testing.T) {
Expand All @@ -206,7 +329,7 @@ func TestBreaking_MaxLengthBothNil(t *testing.T) {
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.True(t, d.Empty())
require.Empty(t, d)
}

func TestBreaking_MinItemsSmaller(t *testing.T) {
Expand All @@ -220,7 +343,7 @@ func TestBreaking_MinItemsSmaller(t *testing.T) {
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.True(t, d.Empty())
require.Empty(t, d)
}

func TestBreaking_MinItemsGreater(t *testing.T) {
Expand All @@ -234,5 +357,5 @@ func TestBreaking_MinItemsGreater(t *testing.T) {
BreakingOnly: true,
}, s1, s2)
require.NoError(t, err)
require.False(t, d.Empty())
require.NotEmpty(t, d)
}
8 changes: 0 additions & 8 deletions diff/headers_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ func (headersDiff *HeadersDiff) Empty() bool {
len(headersDiff.Modified) == 0
}

func (headersDiff *HeadersDiff) emptyNonBreaking(breakingOnly bool) {
if !breakingOnly {
return
}

headersDiff.Added = nil
}

func (headersDiff *HeadersDiff) removeNonBreaking() {

if headersDiff.Empty() {
Expand Down
Loading

0 comments on commit 0b9c21e

Please sign in to comment.