sigs.k8s.io/cluster-api@v1.7.1/util/collections/machine_collection_test.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package collections_test
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	. "github.com/onsi/gomega"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/utils/ptr"
    26  
    27  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    28  	"sigs.k8s.io/cluster-api/util/collections"
    29  )
    30  
    31  func TestMachineCollection(t *testing.T) {
    32  	t.Run("SortedByAge", func(t *testing.T) {
    33  		t.Run("should return the same number of machines as are in the collection", func(t *testing.T) {
    34  			g := NewWithT(t)
    35  			collection := machines()
    36  			sortedMachines := collection.SortedByCreationTimestamp()
    37  			g.Expect(sortedMachines).To(HaveLen(len(collection)))
    38  			g.Expect(sortedMachines[0].Name).To(Equal("machine-1"))
    39  			g.Expect(sortedMachines[len(sortedMachines)-1].Name).To(Equal("machine-5"))
    40  		})
    41  	})
    42  	t.Run("Difference", func(t *testing.T) {
    43  		t.Run("should return the collection with elements of the second collection removed", func(t *testing.T) {
    44  			g := NewWithT(t)
    45  			collection := machines()
    46  			c2 := collection.Filter(func(m *clusterv1.Machine) bool {
    47  				return m.Name != "machine-1"
    48  			})
    49  			c3 := collection.Difference(c2)
    50  			// does not mutate
    51  			g.Expect(collection.Names()).To(ContainElement("machine-1"))
    52  			g.Expect(c3.Names()).To(ConsistOf("machine-1"))
    53  		})
    54  	})
    55  	t.Run("Names", func(t *testing.T) {
    56  		t.Run("should return a slice of names of each machine in the collection", func(t *testing.T) {
    57  			g := NewWithT(t)
    58  			g.Expect(collections.New().Names()).To(BeEmpty())
    59  			g.Expect(collections.FromMachines(machine("1"), machine("2")).Names()).To(ConsistOf("1", "2"))
    60  		})
    61  	})
    62  }
    63  
    64  func TestMachinesLowestVersion(t *testing.T) {
    65  	tests := []struct {
    66  		name     string
    67  		machines collections.Machines
    68  		expected *string
    69  	}{
    70  		{
    71  			name:     "return empty for empty machines collection",
    72  			machines: collections.New(),
    73  			expected: nil,
    74  		},
    75  		{
    76  			name: "return empty if machines dont have version",
    77  			machines: func() collections.Machines {
    78  				machines := collections.New()
    79  				machines.Insert(&clusterv1.Machine{})
    80  				return machines
    81  			}(),
    82  			expected: nil,
    83  		},
    84  		{
    85  			name: "return lowest version from machines",
    86  			machines: func() collections.Machines {
    87  				machines := collections.New()
    88  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-1"}, Spec: clusterv1.MachineSpec{
    89  					Version: ptr.To("1.20"),
    90  				}})
    91  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-2"}, Spec: clusterv1.MachineSpec{
    92  					Version: ptr.To("1.19.8"),
    93  				}})
    94  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-3"}, Spec: clusterv1.MachineSpec{
    95  					Version: ptr.To(""),
    96  				}})
    97  				return machines
    98  			}(),
    99  			expected: ptr.To("1.19.8"),
   100  		},
   101  		{
   102  			name: "return lowest version from machines with pre release versions",
   103  			machines: func() collections.Machines {
   104  				machines := collections.New()
   105  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-1"}, Spec: clusterv1.MachineSpec{
   106  					Version: ptr.To("1.20.1"),
   107  				}})
   108  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-2"}, Spec: clusterv1.MachineSpec{
   109  					Version: ptr.To("1.20.1-alpha.1"),
   110  				}})
   111  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-3"}, Spec: clusterv1.MachineSpec{
   112  					Version: ptr.To(""),
   113  				}})
   114  				return machines
   115  			}(),
   116  			expected: ptr.To("1.20.1-alpha.1"),
   117  		},
   118  		{
   119  			name: "return lowest version from machines with build identifier versions",
   120  			machines: func() collections.Machines {
   121  				machines := collections.New()
   122  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-1"}, Spec: clusterv1.MachineSpec{
   123  					Version: ptr.To("1.20.1+xyz.2"),
   124  				}})
   125  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-2"}, Spec: clusterv1.MachineSpec{
   126  					Version: ptr.To("1.20.1+xyz.1"),
   127  				}})
   128  				machines.Insert(&clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "machine-3"}, Spec: clusterv1.MachineSpec{
   129  					Version: ptr.To(""),
   130  				}})
   131  				return machines
   132  			}(),
   133  			expected: ptr.To("1.20.1+xyz.1"),
   134  		},
   135  	}
   136  
   137  	for _, tt := range tests {
   138  		t.Run(tt.name, func(t *testing.T) {
   139  			g := NewWithT(t)
   140  			g.Expect(tt.machines.LowestVersion()).To(Equal(tt.expected))
   141  		})
   142  	}
   143  }
   144  
   145  /* Helper functions to build machine objects for tests. */
   146  
   147  type machineOpt func(*clusterv1.Machine)
   148  
   149  func withCreationTimestamp(timestamp metav1.Time) machineOpt {
   150  	return func(m *clusterv1.Machine) {
   151  		m.CreationTimestamp = timestamp
   152  	}
   153  }
   154  
   155  func machine(name string, opts ...machineOpt) *clusterv1.Machine {
   156  	m := &clusterv1.Machine{
   157  		ObjectMeta: metav1.ObjectMeta{
   158  			Name: name,
   159  		},
   160  	}
   161  	for _, opt := range opts {
   162  		opt(m)
   163  	}
   164  	return m
   165  }
   166  
   167  func machines() collections.Machines {
   168  	return collections.Machines{
   169  		"machine-4": machine("machine-4", withCreationTimestamp(metav1.Time{Time: time.Date(2018, 04, 02, 03, 04, 05, 06, time.UTC)})),
   170  		"machine-5": machine("machine-5", withCreationTimestamp(metav1.Time{Time: time.Date(2018, 05, 02, 03, 04, 05, 06, time.UTC)})),
   171  		"machine-2": machine("machine-2", withCreationTimestamp(metav1.Time{Time: time.Date(2018, 02, 02, 03, 04, 05, 06, time.UTC)})),
   172  		"machine-1": machine("machine-1", withCreationTimestamp(metav1.Time{Time: time.Date(2018, 01, 02, 03, 04, 05, 06, time.UTC)})),
   173  		"machine-3": machine("machine-3", withCreationTimestamp(metav1.Time{Time: time.Date(2018, 03, 02, 03, 04, 05, 06, time.UTC)})),
   174  	}
   175  }