mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-07-16 17:33:14 +00:00
Merge pull request #2117 from seans3/inventory-set
Adds new InventorySet abstraction
This commit is contained in:
@@ -6,6 +6,7 @@ package kubectlcobra
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@@ -81,3 +82,99 @@ func (i *Inventory) String() string {
|
|||||||
i.GroupKind.Group, fieldSeparator,
|
i.GroupKind.Group, fieldSeparator,
|
||||||
i.GroupKind.Kind)
|
i.GroupKind.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InventorySet encapsulates a grouping of unique Inventory
|
||||||
|
// structs. Organizes the Inventory structs with a map,
|
||||||
|
// which ensures there are no duplicates. Allows set
|
||||||
|
// operations such as merging sets and subtracting sets.
|
||||||
|
type InventorySet struct {
|
||||||
|
set map[string]*Inventory
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInventorySet returns a pointer to an InventorySet
|
||||||
|
// struct grouping the passed Inventory items.
|
||||||
|
func NewInventorySet(items []*Inventory) *InventorySet {
|
||||||
|
invSet := InventorySet{set: map[string]*Inventory{}}
|
||||||
|
invSet.AddItems(items)
|
||||||
|
return &invSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetItems returns the set of pointers to Inventory
|
||||||
|
// structs.
|
||||||
|
func (is *InventorySet) GetItems() []*Inventory {
|
||||||
|
items := []*Inventory{}
|
||||||
|
for _, item := range is.set {
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddItems adds Inventory structs to the set which
|
||||||
|
// are not already in the set.
|
||||||
|
func (is *InventorySet) AddItems(items []*Inventory) {
|
||||||
|
for _, item := range items {
|
||||||
|
if item != nil {
|
||||||
|
is.set[item.String()] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteItem removes an Inventory struct from the
|
||||||
|
// set if it exists in the set. Returns true if the
|
||||||
|
// Inventory item was deleted, false if it did not exist
|
||||||
|
// in the set.
|
||||||
|
func (is *InventorySet) DeleteItem(item *Inventory) bool {
|
||||||
|
if item == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, ok := is.set[item.String()]; ok {
|
||||||
|
delete(is.set, item.String())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge combines the unique set of Inventory items from the
|
||||||
|
// current set with the passed "other" set, returning a new
|
||||||
|
// set or error. Returns an error if the passed set to merge
|
||||||
|
// is nil.
|
||||||
|
func (is *InventorySet) Merge(other *InventorySet) (*InventorySet, error) {
|
||||||
|
if other == nil {
|
||||||
|
return nil, fmt.Errorf("InventorySet to merge is nil.")
|
||||||
|
}
|
||||||
|
// Copy the current InventorySet into result
|
||||||
|
result := NewInventorySet(is.GetItems())
|
||||||
|
result.AddItems(other.GetItems())
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract removes the Inventory items in the "other" set from the
|
||||||
|
// current set, returning a new set. This does not modify the current
|
||||||
|
// set. Returns an error if the passed set to subtract is nil.
|
||||||
|
func (is *InventorySet) Subtract(other *InventorySet) (*InventorySet, error) {
|
||||||
|
if other == nil {
|
||||||
|
return nil, fmt.Errorf("InventorySet to subtract is nil.")
|
||||||
|
}
|
||||||
|
// Copy the current InventorySet into result
|
||||||
|
result := NewInventorySet(is.GetItems())
|
||||||
|
// Remove each item in "other" which exists in "result"
|
||||||
|
for _, item := range other.GetItems() {
|
||||||
|
result.DeleteItem(item)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string describing set of Inventory structs.
|
||||||
|
func (is *InventorySet) String() string {
|
||||||
|
strs := []string{}
|
||||||
|
for _, item := range is.GetItems() {
|
||||||
|
strs = append(strs, item.String())
|
||||||
|
}
|
||||||
|
sort.Strings(strs)
|
||||||
|
return strings.Join(strs, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the number of Inventory structs in the set.
|
||||||
|
func (is *InventorySet) Size() int {
|
||||||
|
return len(is.set)
|
||||||
|
}
|
||||||
|
|||||||
@@ -216,3 +216,274 @@ func TestParseInventory(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var inventory1 = Inventory{
|
||||||
|
Namespace: "test-namespace",
|
||||||
|
Name: "test-inv-1",
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "apps",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var inventory2 = Inventory{
|
||||||
|
Namespace: "test-namespace",
|
||||||
|
Name: "test-inv-2",
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Pod",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var inventory3 = Inventory{
|
||||||
|
Namespace: "test-namespace",
|
||||||
|
Name: "test-inv-3",
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "",
|
||||||
|
Kind: "Service",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var inventory4 = Inventory{
|
||||||
|
Namespace: "test-namespace",
|
||||||
|
Name: "test-inv-4",
|
||||||
|
GroupKind: schema.GroupKind{
|
||||||
|
Group: "apps",
|
||||||
|
Kind: "DaemonSet",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewInventorySet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
items []*Inventory
|
||||||
|
expectedStr string
|
||||||
|
expectedSize int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
items: []*Inventory{},
|
||||||
|
expectedStr: "",
|
||||||
|
expectedSize: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: []*Inventory{&inventory1},
|
||||||
|
expectedStr: "test-namespace_test-inv-1_apps_Deployment",
|
||||||
|
expectedSize: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: []*Inventory{&inventory1, &inventory2},
|
||||||
|
expectedStr: "test-namespace_test-inv-1_apps_Deployment, test-namespace_test-inv-2__Pod",
|
||||||
|
expectedSize: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
invSet := NewInventorySet(test.items)
|
||||||
|
actualStr := invSet.String()
|
||||||
|
actualSize := invSet.Size()
|
||||||
|
if test.expectedStr != actualStr {
|
||||||
|
t.Errorf("Expected InventorySet (%s), got (%s)\n", test.expectedStr, actualStr)
|
||||||
|
}
|
||||||
|
if test.expectedSize != actualSize {
|
||||||
|
t.Errorf("Expected InventorySet size (%d), got (%d)\n", test.expectedSize, actualSize)
|
||||||
|
}
|
||||||
|
actualItems := invSet.GetItems()
|
||||||
|
if len(test.items) != len(actualItems) {
|
||||||
|
t.Errorf("Expected num inventory items (%d), got (%d)\n", len(test.items), len(actualItems))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInventorySetAddItems(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
initialItems []*Inventory
|
||||||
|
addItems []*Inventory
|
||||||
|
expectedItems []*Inventory
|
||||||
|
}{
|
||||||
|
// Adding no items to empty inventory set.
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{},
|
||||||
|
addItems: []*Inventory{},
|
||||||
|
expectedItems: []*Inventory{},
|
||||||
|
},
|
||||||
|
// Adding item to empty inventory set.
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{},
|
||||||
|
addItems: []*Inventory{&inventory1},
|
||||||
|
expectedItems: []*Inventory{&inventory1},
|
||||||
|
},
|
||||||
|
// Adding no items does not change the inventory set
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1},
|
||||||
|
addItems: []*Inventory{},
|
||||||
|
expectedItems: []*Inventory{&inventory1},
|
||||||
|
},
|
||||||
|
// Adding an item which alread exists does not increase size.
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
addItems: []*Inventory{&inventory1},
|
||||||
|
expectedItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
addItems: []*Inventory{&inventory3, &inventory4},
|
||||||
|
expectedItems: []*Inventory{&inventory1, &inventory2, &inventory3, &inventory4},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
invSet := NewInventorySet(test.initialItems)
|
||||||
|
invSet.AddItems(test.addItems)
|
||||||
|
if len(test.expectedItems) != invSet.Size() {
|
||||||
|
t.Errorf("Expected num inventory items (%d), got (%d)\n", len(test.expectedItems), invSet.Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInventorySetDeleteItem(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
initialItems []*Inventory
|
||||||
|
deleteItem *Inventory
|
||||||
|
expected bool
|
||||||
|
expectedItems []*Inventory
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{},
|
||||||
|
deleteItem: nil,
|
||||||
|
expected: false,
|
||||||
|
expectedItems: []*Inventory{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{},
|
||||||
|
deleteItem: &inventory1,
|
||||||
|
expected: false,
|
||||||
|
expectedItems: []*Inventory{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory2},
|
||||||
|
deleteItem: &inventory1,
|
||||||
|
expected: false,
|
||||||
|
expectedItems: []*Inventory{&inventory2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1},
|
||||||
|
deleteItem: &inventory1,
|
||||||
|
expected: true,
|
||||||
|
expectedItems: []*Inventory{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
deleteItem: &inventory1,
|
||||||
|
expected: true,
|
||||||
|
expectedItems: []*Inventory{&inventory2},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
invSet := NewInventorySet(test.initialItems)
|
||||||
|
actual := invSet.DeleteItem(test.deleteItem)
|
||||||
|
if test.expected != actual {
|
||||||
|
t.Errorf("Expected return value (%t), got (%t)\n", test.expected, actual)
|
||||||
|
}
|
||||||
|
if len(test.expectedItems) != invSet.Size() {
|
||||||
|
t.Errorf("Expected num inventory items (%d), got (%d)\n", len(test.expectedItems), invSet.Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInventorySetMerge(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
set1 []*Inventory
|
||||||
|
set2 []*Inventory
|
||||||
|
merged []*Inventory
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
set1: []*Inventory{},
|
||||||
|
set2: []*Inventory{},
|
||||||
|
merged: []*Inventory{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
set1: []*Inventory{},
|
||||||
|
set2: []*Inventory{&inventory1},
|
||||||
|
merged: []*Inventory{&inventory1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
set1: []*Inventory{&inventory1},
|
||||||
|
set2: []*Inventory{},
|
||||||
|
merged: []*Inventory{&inventory1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
set1: []*Inventory{&inventory1, &inventory2},
|
||||||
|
set2: []*Inventory{&inventory1},
|
||||||
|
merged: []*Inventory{&inventory1, &inventory2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
set1: []*Inventory{&inventory1, &inventory2},
|
||||||
|
set2: []*Inventory{&inventory1, &inventory2},
|
||||||
|
merged: []*Inventory{&inventory1, &inventory2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
set1: []*Inventory{&inventory1, &inventory2},
|
||||||
|
set2: []*Inventory{&inventory3, &inventory4},
|
||||||
|
merged: []*Inventory{&inventory1, &inventory2, &inventory3, &inventory4},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
invSet1 := NewInventorySet(test.set1)
|
||||||
|
invSet2 := NewInventorySet(test.set2)
|
||||||
|
expected := NewInventorySet(test.merged)
|
||||||
|
merged, _ := invSet1.Merge(invSet2)
|
||||||
|
if expected.Size() != merged.Size() {
|
||||||
|
t.Errorf("Expected merged inventory set size (%d), got (%d)\n", expected.Size(), merged.Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInventorySetSubtract(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
initialItems []*Inventory
|
||||||
|
subtractItems []*Inventory
|
||||||
|
expected []*Inventory
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{},
|
||||||
|
subtractItems: []*Inventory{},
|
||||||
|
expected: []*Inventory{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{},
|
||||||
|
subtractItems: []*Inventory{&inventory1},
|
||||||
|
expected: []*Inventory{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1},
|
||||||
|
subtractItems: []*Inventory{},
|
||||||
|
expected: []*Inventory{&inventory1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
subtractItems: []*Inventory{&inventory1},
|
||||||
|
expected: []*Inventory{&inventory2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
subtractItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
expected: []*Inventory{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initialItems: []*Inventory{&inventory1, &inventory2},
|
||||||
|
subtractItems: []*Inventory{&inventory3, &inventory4},
|
||||||
|
expected: []*Inventory{&inventory1, &inventory2},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
invInitialItems := NewInventorySet(test.initialItems)
|
||||||
|
invSubtractItems := NewInventorySet(test.subtractItems)
|
||||||
|
expected := NewInventorySet(test.expected)
|
||||||
|
actual, _ := invInitialItems.Subtract(invSubtractItems)
|
||||||
|
if expected.Size() != actual.Size() {
|
||||||
|
t.Errorf("Expected subtracted inventory set size (%d), got (%d)\n", expected.Size(), actual.Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user