Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support apiVersion and kind in lists of Kubernetes items #323

Merged
merged 9 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions assets/kubernetes/lists-versioned-crds/from.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
apiVersion: v1
kind: List
metadata:
name: ingress-class
items:
- apiVersion: v2
kind: kindv2
metadata:
name: item
labels:
id: 2
- apiVersion: v1
kind: kindv1
metadata:
name: item
labels:
id: 1
18 changes: 18 additions & 0 deletions assets/kubernetes/lists-versioned-crds/to.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
apiVersion: v1
kind: List
metadata:
name: ingress-class
items:
- apiVersion: v1
kind: kindv1
metadata:
name: item
labels:
id: 1
- apiVersion: v2
kind: kindv2
metadata:
name: item
labels:
id: 2
File renamed without changes.
File renamed without changes.
11 changes: 11 additions & 0 deletions assets/kubernetes/multi-docs-versioned-crds/from.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: v1beta1
kind: some-kind
metadata:
name: some-item

---
apiVersion: v1alpha1
kind: some-kind
metadata:
name: some-item
11 changes: 11 additions & 0 deletions assets/kubernetes/multi-docs-versioned-crds/to.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: v1alpha1
kind: some-kind
metadata:
name: some-item

---
apiVersion: v1beta1
kind: some-kind
metadata:
name: some-item
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion internal/cmd/cmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ yaml.map.whitespaces

It("should show a report when filtering and a document has been removed between inputs", func() {
expected := `
spec.replicas (Deployment/default/test)
spec.replicas (apps/v1/Deployment/test)
± value change
- 2
+ 3
Expand Down
77 changes: 63 additions & 14 deletions pkg/dyff/compare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/gonvenience/ytbx"

"github.com/homeport/dyff/pkg/dyff"

"github.com/gonvenience/ytbx"
yamlv3 "gopkg.in/yaml.v3"
)

var nullNode = &yamlv3.Node{
Kind: yamlv3.ScalarNode,
Tag: "!!null",
Value: "null",
}

var _ = Describe("Core/Compare", func() {
Describe("Difference between YAMLs", func() {
Context("Given two simple YAML structures", func() {
Expand Down Expand Up @@ -524,8 +531,8 @@ resource_pools:

Context("Given two files", func() {
It("should return differences in raw texts", func() {
from := file("../../assets/raw-text/from.txt")
to := file("../../assets/raw-text/to.txt")
from := file(assets("raw-text/from.txt"))
to := file(assets("raw-text/to.txt"))
Expect(from.Documents).To(HaveLen(1))
Expect(to.Documents).To(HaveLen(1))

Expand Down Expand Up @@ -605,6 +612,21 @@ listY: [ Yo, Yo, Yo ]
}))
})

It("should return changes where one of the items is null", func() {
from := yml(`foo: null`)
to := yml(`foo: "bar"`)
results, err := compare(from, to)
Expect(err).To(BeNil())
Expect(results).NotTo(BeNil())
Expect(results).To(HaveLen(1))
Expect(results[0]).To(BeSameDiffAs(singleDiff(
"/foo",
dyff.MODIFICATION,
nullNode,
"bar",
)))
})

It("should not return order changes in named entry lists in case the ignore option is enabled", func() {
results, err := compare(
yml(`list: [ {name: A}, {name: C}, {name: B}, {name: D}, {name: E} ]`),
Expand Down Expand Up @@ -635,15 +657,24 @@ listY: [ Yo, Yo, Yo ]
Expect(isSameDetail(actual, expected)).To(BeTrue())
})

It("should process simple lists independent of other compare settings", func() {
from := yml(`list: [ A, B, C, D, E ]`)
to := yml(`list: [ A, B, C, D, E ]`)

results, err := compare(from, to, dyff.KubernetesEntityDetection(false))
Expect(err).To(BeNil())
Expect(results).To(BeNil())
})

It("should return all differences between the files with multiple documents", func() {
results, err := dyff.CompareInputFiles(file("../../assets/kubernetes-yaml/from.yml"), file("../../assets/kubernetes-yaml/to.yml"))
expected := []dyff.Diff{
singleDiff("#0/spec/template/spec/containers/name=registry/resources/limits/cpu", dyff.MODIFICATION, "100m", "1000m"),
singleDiff("#0/spec/template/spec/containers/name=registry/resources/limits/memory", dyff.MODIFICATION, "100Mi", "10Gi"),
singleDiff("#0/spec/template/spec/containers/name=registry/ports", dyff.ADDITION, nil, list(`[ {containerPort: 5001, name: backdoor, protocol: TCP} ]`)),
singleDiff("#1/spec/ports", dyff.ADDITION, nil, list(`[ {name: backdoor, port: 5001, protocol: TCP} ]`)),
}

results, err := dyff.CompareInputFiles(file(assets("kubernetes/multi-docs/from.yml")), file(assets("kubernetes/multi-docs/to.yml")))
Expect(err).To(BeNil())
Expect(results).NotTo(BeNil())
Expect(results.Diffs).NotTo(BeNil())
Expand All @@ -664,8 +695,8 @@ listY: [ Yo, Yo, Yo ]

It("should return differences in named lists even if no standard identifier is used", func() {
results, err := dyff.CompareInputFiles(
file("../../assets/prometheus/from.yml"),
file("../../assets/prometheus/to.yml"),
file(assets("prometheus/from.yml")),
file(assets("prometheus/to.yml")),
)

Expect(err).To(BeNil())
Expand Down Expand Up @@ -713,8 +744,8 @@ listY: [ Yo, Yo, Yo ]

It("should fail to find the non-standard identifier if the threshold is too high", func() {
report, err := dyff.CompareInputFiles(
file("../../assets/prometheus/from.yml"),
file("../../assets/prometheus/to.yml"),
file(assets("prometheus/from.yml")),
file(assets("prometheus/to.yml")),
dyff.NonStandardIdentifierGuessCountThreshold(8),
)

Expand Down Expand Up @@ -821,8 +852,8 @@ b: bar
Context("two YAML structures with Kubernetes lists", func() {
It("should identify individual list entries based on the nested name field in the respective entry metadata", func() {
from, to := loadFiles(
assets("kubernetes-lists", "pods", "from.yml"),
assets("kubernetes-lists", "pods", "to.yml"),
assets("kubernetes", "lists", "from.yml"),
assets("kubernetes", "lists", "to.yml"),
)

results, err := dyff.CompareInputFiles(from, to, dyff.KubernetesEntityDetection(true))
Expand All @@ -832,16 +863,34 @@ b: bar
Expect(results.Diffs[0]).To(BeSameDiffAs(singleDiff(
"#0/items",
dyff.ORDERCHANGE,
dyff.AsSequenceNode("foo-2", "foo-1"),
dyff.AsSequenceNode("foo-1", "foo-2"),
dyff.AsSequenceNode("v1/Pod/foobar/foo-2", "v1/Pod/foobar/foo-1"),
dyff.AsSequenceNode("v1/Pod/foobar/foo-1", "v1/Pod/foobar/foo-2"),
)))
Expect(results.Diffs[1]).To(BeSameDiffAs(singleDiff(
"/items/metadata.name=foo-1/metadata/labels/foo",
"/items/resource=v1\\/Pod\\/foobar\\/foo-1/metadata/labels/foo",
dyff.MODIFICATION,
"bAr",
"bar",
)))
})

It("should detect Kubernetes items by their apiVersion, kind, and name", func() {
from, to := loadFiles(
assets("kubernetes", "lists-versioned-crds", "from.yml"),
assets("kubernetes", "lists-versioned-crds", "to.yml"),
)

results, err := dyff.CompareInputFiles(from, to, dyff.KubernetesEntityDetection(true))
Expect(err).ToNot(HaveOccurred())

Expect(results.Diffs).To(HaveLen(1))
Expect(results.Diffs[0]).To(BeSameDiffAs(singleDiff(
"#0/items",
dyff.ORDERCHANGE,
dyff.AsSequenceNode("v2/kindv2/item", "v1/kindv1/item"),
dyff.AsSequenceNode("v1/kindv1/item", "v2/kindv2/item"),
)))
})
})

Context("checking known issues of compare", func() {
Expand Down
Loading
Loading