what-changed operational

the code is working, the tests are passing. There is a lot more to check, but it's a good time to bring the feature into main.
This commit is contained in:
Dave Shanley
2022-11-18 10:47:39 -05:00
parent b510be3563
commit 9d8d6e36ea
8 changed files with 133 additions and 69 deletions

View File

@@ -246,17 +246,15 @@ func (s *Schema) Hash() [32]byte {
// hash polymorphic data
if len(s.OneOf.Value) > 0 {
oneOfKeys := make([]string, len(s.OneOf.Value))
oneOfEntities := make(map[string]*Schema)
oneOfEntities := make(map[string]*SchemaProxy)
z = 0
for i := range s.OneOf.Value {
g := s.OneOf.Value[i].Value
if !g.IsSchemaReference() {
k := g.Schema()
r := low.GenerateHashString(k)
oneOfEntities[r] = k
oneOfKeys[z] = r
z++
}
r := low.GenerateHashString(g)
oneOfEntities[r] = g
oneOfKeys[z] = r
z++
}
sort.Strings(oneOfKeys)
for k := range oneOfKeys {
@@ -266,17 +264,15 @@ func (s *Schema) Hash() [32]byte {
if len(s.AllOf.Value) > 0 {
allOfKeys := make([]string, len(s.AllOf.Value))
allOfEntities := make(map[string]*Schema)
allOfEntities := make(map[string]*SchemaProxy)
z = 0
for i := range s.AllOf.Value {
g := s.AllOf.Value[i].Value
if !g.IsSchemaReference() {
k := g.Schema()
r := low.GenerateHashString(k)
allOfEntities[r] = k
allOfKeys[z] = r
z++
}
r := low.GenerateHashString(g)
allOfEntities[r] = g
allOfKeys[z] = r
z++
}
sort.Strings(allOfKeys)
for k := range allOfKeys {
@@ -286,17 +282,15 @@ func (s *Schema) Hash() [32]byte {
if len(s.AnyOf.Value) > 0 {
anyOfKeys := make([]string, len(s.AnyOf.Value))
anyOfEntities := make(map[string]*Schema)
anyOfEntities := make(map[string]*SchemaProxy)
z = 0
for i := range s.AnyOf.Value {
g := s.AnyOf.Value[i].Value
if !g.IsSchemaReference() {
k := g.Schema()
r := low.GenerateHashString(k)
anyOfEntities[r] = k
anyOfKeys[z] = r
z++
}
r := low.GenerateHashString(g)
anyOfEntities[r] = g
anyOfKeys[z] = r
z++
}
sort.Strings(anyOfKeys)
for k := range anyOfKeys {
@@ -306,17 +300,15 @@ func (s *Schema) Hash() [32]byte {
if len(s.Not.Value) > 0 {
notKeys := make([]string, len(s.Not.Value))
notEntities := make(map[string]*Schema)
notEntities := make(map[string]*SchemaProxy)
z = 0
for i := range s.Not.Value {
g := s.Not.Value[i].Value
if !g.IsSchemaReference() {
k := g.Schema()
r := low.GenerateHashString(k)
notEntities[r] = k
notKeys[z] = r
z++
}
r := low.GenerateHashString(g)
notEntities[r] = g
notKeys[z] = r
z++
}
sort.Strings(notKeys)
for k := range notKeys {
@@ -326,17 +318,14 @@ func (s *Schema) Hash() [32]byte {
if len(s.Items.Value) > 0 {
itemsKeys := make([]string, len(s.Items.Value))
itemsEntities := make(map[string]*Schema)
itemsEntities := make(map[string]*SchemaProxy)
z = 0
for i := range s.Items.Value {
g := s.Items.Value[i].Value
if !g.IsSchemaReference() {
k := g.Schema()
r := low.GenerateHashString(k)
itemsEntities[r] = k
itemsKeys[z] = r
z++
}
r := low.GenerateHashString(g)
itemsEntities[r] = g
itemsKeys[z] = r
z++
}
sort.Strings(itemsKeys)
for k := range itemsKeys {

View File

@@ -62,7 +62,7 @@ func (h *Header) Hash() [32]byte {
f = append(f, fmt.Sprint(h.Explode.Value))
f = append(f, fmt.Sprint(h.AllowReserved.Value))
if h.Schema.Value != nil {
f = append(f, low.GenerateHashString(h.Schema.Value.Schema()))
f = append(f, low.GenerateHashString(h.Schema.Value))
}
if h.Example.Value != nil {
f = append(f, fmt.Sprint(h.Example.Value))

View File

@@ -98,7 +98,7 @@ func (mt *MediaType) Build(root *yaml.Node, idx *index.SpecIndex) error {
func (mt *MediaType) Hash() [32]byte {
var f []string
if mt.Schema.Value != nil {
f = append(f, low.GenerateHashString(mt.Schema.Value.Schema()))
f = append(f, low.GenerateHashString(mt.Schema.Value))
}
if mt.Example.Value != nil {
f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(mt.Example.Value)))))

View File

@@ -9,6 +9,7 @@ import (
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"sort"
"strings"
)
@@ -63,9 +64,14 @@ func (s *Server) Build(root *yaml.Node, idx *index.SpecIndex) error {
// Hash will return a consistent SHA256 Hash of the Server object
func (s *Server) Hash() [32]byte {
var f []string
keys := make([]string, len(s.Variables.Value))
z := 0
for k := range s.Variables.Value {
f = append(f, low.GenerateHashString(s.Variables.Value[k].Value))
keys[z] = low.GenerateHashString(s.Variables.Value[k].Value)
z++
}
sort.Strings(keys)
f = append(f, keys...)
if !s.URL.IsEmpty() {
f = append(f, s.URL.Value)
}

View File

@@ -102,7 +102,7 @@ paths:
unexpectedError:
summary: oh my goodness
value:
message: something went terribly wrong my friend, no new burger for you.
message: something went terribly wrong my friend, no new burger for you. mate.
"422":
description: Unprocessable entity
content:

View File

@@ -4,8 +4,11 @@
package model
import (
"fmt"
"github.com/pb33f/libopenapi/datamodel/low/base"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/utils"
"sort"
)
// ExampleChanges represent changes to an Example object, part of an OpenAPI specification.
@@ -60,16 +63,56 @@ func CompareExamples(l, r *base.Example) *ExampleChanges {
})
// Value
props = append(props, &PropertyCheck{
LeftNode: l.Value.ValueNode,
RightNode: r.Value.ValueNode,
Label: v3.ValueLabel,
Changes: &changes,
Breaking: false,
Original: l,
New: r,
})
if utils.IsNodeMap(l.Value.ValueNode) && utils.IsNodeMap(r.Value.ValueNode) {
lKeys := make([]string, len(l.Value.ValueNode.Content)/2)
rKeys := make([]string, len(r.Value.ValueNode.Content)/2)
z := 0
for k := range l.Value.ValueNode.Content {
if k%2 == 0 {
lKeys[z] = fmt.Sprintf("%v-%v", l.Value.ValueNode.Content[k].Value, l.Value.ValueNode.Content[k+1].Value)
z++
} else {
continue
}
}
z = 0
for k := range r.Value.ValueNode.Content {
if k%2 == 0 {
rKeys[z] = fmt.Sprintf("%v-%v", r.Value.ValueNode.Content[k].Value, r.Value.ValueNode.Content[k+1].Value)
z++
} else {
continue
}
}
sort.Strings(lKeys)
sort.Strings(rKeys)
if (len(lKeys) > len(rKeys)) || (len(rKeys) > len(lKeys)) {
CreateChange(&changes, Modified, v3.ValueLabel,
l.Value.GetValueNode(), r.Value.GetValueNode(), false, l.Value.GetValue(), r.Value.GetValue())
}
for k := range lKeys {
if lKeys[k] != rKeys[k] {
CreateChange(&changes, Modified, v3.ValueLabel,
l.Value.GetValueNode(), r.Value.GetValueNode(), false, l.Value.GetValue(), r.Value.GetValue())
}
}
for k := range rKeys {
if k >= len(lKeys) {
CreateChange(&changes, Modified, v3.ValueLabel,
nil, r.Value.GetValueNode(), false, nil, r.Value.GetValue())
}
}
} else {
props = append(props, &PropertyCheck{
LeftNode: l.Value.ValueNode,
RightNode: r.Value.ValueNode,
Label: v3.ValueLabel,
Changes: &changes,
Breaking: false,
Original: l,
New: r,
})
}
// ExternalValue
props = append(props, &PropertyCheck{
LeftNode: l.ExternalValue.ValueNode,

View File

@@ -411,6 +411,9 @@ func checkServers(lServers, rServers low.NodeReference[[]low.ValueReference[*v3.
nil, rServers.ValueNode, false, nil,
rServers.Value)
}
if len(serverChanges) <= 0 {
return nil
}
return serverChanges
}

View File

@@ -3,18 +3,41 @@
package what_changed
//func TestCompareOpenAPIDocuments(t *testing.T) {
//
// original, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
// modified, _ := ioutil.ReadFile("../test_specs/burgershop.openapi-modified.yaml")
// infoOrig, _ := datamodel.ExtractSpecInfo(original)
// infoMod, _ := datamodel.ExtractSpecInfo(modified)
//
// origDoc, _ := v3.CreateDocument(infoOrig)
// modDoc, _ := v3.CreateDocument(infoMod)
//
// changes := CompareOpenAPIDocuments(origDoc, modDoc)
//
// assert.Nil(t, changes)
//
//}
import (
"github.com/pb33f/libopenapi/datamodel"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/stretchr/testify/assert"
"io/ioutil"
"testing"
)
func TestCompareOpenAPIDocuments(t *testing.T) {
original, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
modified, _ := ioutil.ReadFile("../test_specs/burgershop.openapi-modified.yaml")
infoOrig, _ := datamodel.ExtractSpecInfo(original)
infoMod, _ := datamodel.ExtractSpecInfo(modified)
origDoc, _ := v3.CreateDocument(infoOrig)
modDoc, _ := v3.CreateDocument(infoMod)
changes := CompareOpenAPIDocuments(origDoc, modDoc)
assert.Equal(t, 1, changes.TotalChanges())
assert.Equal(t, 0, changes.TotalBreakingChanges())
}
func Benchmark_CompareOpenAPIDocuments(b *testing.B) {
original, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
modified, _ := ioutil.ReadFile("../test_specs/burgershop.openapi-modified.yaml")
infoOrig, _ := datamodel.ExtractSpecInfo(original)
infoMod, _ := datamodel.ExtractSpecInfo(modified)
origDoc, _ := v3.CreateDocument(infoOrig)
modDoc, _ := v3.CreateDocument(infoMod)
for i := 0; i < b.N; i++ {
CompareOpenAPIDocuments(origDoc, modDoc)
}
}