mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-09-13 11:34:54 +00:00
Testing: Add missing unit tests for pkg/itemblock
Add comprehensive unit tests for pkg/itemblock which previously had zero test coverage. The new tests cover AddUnstructured and FindItem methods with 14 test cases across 3 test functions, including preferred GVR ordering, nil item handling, namespace/name filtering, unparseable apiVersion handling, and cluster-scoped resource matching. Fixes #10418 Signed-off-by: opbot_xd <awasthikrishna23052005@gmail.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Add unit tests for pkg/itemblock
|
||||
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package itemblock
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// newUnstructuredItem creates an unstructured object with the given apiVersion,
|
||||
// kind, namespace, and name for use in tests.
|
||||
func newUnstructuredItem(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"apiVersion": apiVersion,
|
||||
"kind": kind,
|
||||
"metadata": map[string]any{
|
||||
"namespace": namespace,
|
||||
"name": name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddUnstructured(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
items []ItemBlockItem
|
||||
expectedLen int
|
||||
}{
|
||||
{
|
||||
name: "add single item to empty block",
|
||||
items: []ItemBlockItem{
|
||||
{
|
||||
Gr: schema.GroupResource{Group: "apps", Resource: "deployments"},
|
||||
Item: newUnstructuredItem("apps/v1", "Deployment", "default", "nginx"),
|
||||
PreferredGVR: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
},
|
||||
},
|
||||
expectedLen: 1,
|
||||
},
|
||||
{
|
||||
name: "add multiple items",
|
||||
items: []ItemBlockItem{
|
||||
{
|
||||
Gr: schema.GroupResource{Group: "", Resource: "pods"},
|
||||
Item: newUnstructuredItem("v1", "Pod", "default", "pod-1"),
|
||||
PreferredGVR: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"},
|
||||
},
|
||||
{
|
||||
Gr: schema.GroupResource{Group: "", Resource: "services"},
|
||||
Item: newUnstructuredItem("v1", "Service", "kube-system", "kube-dns"),
|
||||
PreferredGVR: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"},
|
||||
},
|
||||
{
|
||||
Gr: schema.GroupResource{Group: "apps", Resource: "deployments"},
|
||||
Item: newUnstructuredItem("apps/v1", "Deployment", "default", "web"),
|
||||
PreferredGVR: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
},
|
||||
},
|
||||
expectedLen: 3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ib := &ItemBlock{
|
||||
Log: logrus.New(),
|
||||
}
|
||||
|
||||
for _, item := range tc.items {
|
||||
ib.AddUnstructured(item.Gr, item.Item, item.PreferredGVR)
|
||||
}
|
||||
|
||||
require.Len(t, ib.Items, tc.expectedLen)
|
||||
|
||||
// Verify each added item matches what was provided
|
||||
for i, item := range tc.items {
|
||||
assert.Equal(t, item.Gr, ib.Items[i].Gr)
|
||||
assert.Equal(t, item.Item, ib.Items[i].Item)
|
||||
assert.Equal(t, item.PreferredGVR, ib.Items[i].PreferredGVR)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindItem(t *testing.T) {
|
||||
podsGR := schema.GroupResource{Group: "", Resource: "pods"}
|
||||
deploymentsGR := schema.GroupResource{Group: "apps", Resource: "deployments"}
|
||||
servicesGR := schema.GroupResource{Group: "", Resource: "services"}
|
||||
|
||||
podsGVR := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
||||
deploymentsGVR := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
existingItems []ItemBlockItem
|
||||
searchGR schema.GroupResource
|
||||
searchNamespace string
|
||||
searchName string
|
||||
expectedCount int
|
||||
// If set, verifies the names in the returned items are in this exact order
|
||||
expectedNames []string
|
||||
}{
|
||||
{
|
||||
name: "find item in empty block returns nil",
|
||||
existingItems: nil,
|
||||
searchGR: podsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "pod-1",
|
||||
expectedCount: 0,
|
||||
},
|
||||
{
|
||||
name: "find matching item by GR, namespace, and name",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: podsGR,
|
||||
Item: newUnstructuredItem("v1", "Pod", "default", "pod-1"),
|
||||
PreferredGVR: podsGVR,
|
||||
},
|
||||
},
|
||||
searchGR: podsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "pod-1",
|
||||
expectedCount: 1,
|
||||
expectedNames: []string{"pod-1"},
|
||||
},
|
||||
{
|
||||
name: "no match when GR differs",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: podsGR,
|
||||
Item: newUnstructuredItem("v1", "Pod", "default", "pod-1"),
|
||||
PreferredGVR: podsGVR,
|
||||
},
|
||||
},
|
||||
searchGR: deploymentsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "pod-1",
|
||||
expectedCount: 0,
|
||||
},
|
||||
{
|
||||
name: "no match when namespace differs",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: podsGR,
|
||||
Item: newUnstructuredItem("v1", "Pod", "default", "pod-1"),
|
||||
PreferredGVR: podsGVR,
|
||||
},
|
||||
},
|
||||
searchGR: podsGR,
|
||||
searchNamespace: "kube-system",
|
||||
searchName: "pod-1",
|
||||
expectedCount: 0,
|
||||
},
|
||||
{
|
||||
name: "no match when name differs",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: podsGR,
|
||||
Item: newUnstructuredItem("v1", "Pod", "default", "pod-1"),
|
||||
PreferredGVR: podsGVR,
|
||||
},
|
||||
},
|
||||
searchGR: podsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "pod-2",
|
||||
expectedCount: 0,
|
||||
},
|
||||
{
|
||||
name: "nil item is skipped",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: podsGR,
|
||||
Item: nil,
|
||||
PreferredGVR: podsGVR,
|
||||
},
|
||||
},
|
||||
searchGR: podsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "pod-1",
|
||||
expectedCount: 0,
|
||||
},
|
||||
{
|
||||
name: "preferred GVR match is returned first",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1beta1", "Deployment", "default", "web"),
|
||||
PreferredGVR: deploymentsGVR, // preferred is v1, item is v1beta1 → non-preferred
|
||||
},
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1", "Deployment", "default", "web"),
|
||||
PreferredGVR: deploymentsGVR, // preferred is v1, item is v1 → preferred match
|
||||
},
|
||||
},
|
||||
searchGR: deploymentsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "web",
|
||||
expectedCount: 2,
|
||||
expectedNames: []string{"web", "web"},
|
||||
},
|
||||
{
|
||||
name: "multiple non-preferred items returned when no preferred match",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1beta1", "Deployment", "default", "web"),
|
||||
PreferredGVR: deploymentsGVR,
|
||||
},
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1beta2", "Deployment", "default", "web"),
|
||||
PreferredGVR: deploymentsGVR,
|
||||
},
|
||||
},
|
||||
searchGR: deploymentsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "web",
|
||||
expectedCount: 2,
|
||||
},
|
||||
{
|
||||
name: "item with unparsable apiVersion is treated as non-preferred",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("not/a/valid/version", "Deployment", "default", "web"),
|
||||
PreferredGVR: deploymentsGVR,
|
||||
},
|
||||
},
|
||||
searchGR: deploymentsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "web",
|
||||
expectedCount: 1,
|
||||
},
|
||||
{
|
||||
name: "only matching GR items are returned from mixed block",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: podsGR,
|
||||
Item: newUnstructuredItem("v1", "Pod", "default", "app"),
|
||||
PreferredGVR: podsGVR,
|
||||
},
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1", "Deployment", "default", "app"),
|
||||
PreferredGVR: deploymentsGVR,
|
||||
},
|
||||
{
|
||||
Gr: servicesGR,
|
||||
Item: newUnstructuredItem("v1", "Service", "default", "app"),
|
||||
PreferredGVR: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"},
|
||||
},
|
||||
},
|
||||
searchGR: deploymentsGR,
|
||||
searchNamespace: "default",
|
||||
searchName: "app",
|
||||
expectedCount: 1,
|
||||
expectedNames: []string{"app"},
|
||||
},
|
||||
{
|
||||
name: "cluster-scoped item found with empty namespace",
|
||||
existingItems: []ItemBlockItem{
|
||||
{
|
||||
Gr: schema.GroupResource{Group: "", Resource: "namespaces"},
|
||||
Item: newUnstructuredItem("v1", "Namespace", "", "production"),
|
||||
PreferredGVR: schema.GroupVersionResource{
|
||||
Group: "", Version: "v1", Resource: "namespaces",
|
||||
},
|
||||
},
|
||||
},
|
||||
searchGR: schema.GroupResource{Group: "", Resource: "namespaces"},
|
||||
searchNamespace: "",
|
||||
searchName: "production",
|
||||
expectedCount: 1,
|
||||
expectedNames: []string{"production"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ib := &ItemBlock{
|
||||
Log: logrus.New(),
|
||||
Items: tc.existingItems,
|
||||
}
|
||||
|
||||
result := ib.FindItem(tc.searchGR, tc.searchNamespace, tc.searchName)
|
||||
|
||||
require.Len(t, result, tc.expectedCount)
|
||||
|
||||
if tc.expectedNames != nil {
|
||||
for i, expectedName := range tc.expectedNames {
|
||||
assert.Equal(t, expectedName, result[i].Item.GetName())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindItemPreferredOrdering(t *testing.T) {
|
||||
deploymentsGR := schema.GroupResource{Group: "apps", Resource: "deployments"}
|
||||
deploymentsGVR := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
|
||||
|
||||
// Insert non-preferred first, preferred second to verify ordering
|
||||
ib := &ItemBlock{
|
||||
Log: logrus.New(),
|
||||
Items: []ItemBlockItem{
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1beta1", "Deployment", "ns", "deploy"),
|
||||
PreferredGVR: deploymentsGVR,
|
||||
},
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1", "Deployment", "ns", "deploy"),
|
||||
PreferredGVR: deploymentsGVR,
|
||||
},
|
||||
{
|
||||
Gr: deploymentsGR,
|
||||
Item: newUnstructuredItem("apps/v1beta2", "Deployment", "ns", "deploy"),
|
||||
PreferredGVR: deploymentsGVR,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result := ib.FindItem(deploymentsGR, "ns", "deploy")
|
||||
|
||||
require.Len(t, result, 3)
|
||||
|
||||
// The preferred match (apps/v1) should be first, regardless of insertion order
|
||||
assert.Equal(t, "apps/v1", result[0].Item.GetAPIVersion(),
|
||||
"preferred GVR match should be returned first")
|
||||
|
||||
// Non-preferred items follow in insertion order
|
||||
assert.Equal(t, "apps/v1beta1", result[1].Item.GetAPIVersion())
|
||||
assert.Equal(t, "apps/v1beta2", result[2].Item.GetAPIVersion())
|
||||
}
|
||||
Reference in New Issue
Block a user