github.com/ironcore-dev/gardener-extension-provider-ironcore@v0.3.2-0.20240314231816-8336447fb9a0/pkg/apis/ironcore/validation/cloudprofile_test.go (about)

     1  // SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package validation
     5  
     6  import (
     7  	"github.com/gardener/gardener/pkg/apis/core"
     8  	. "github.com/onsi/ginkgo/v2"
     9  	. "github.com/onsi/gomega"
    10  	. "github.com/onsi/gomega/gstruct"
    11  	"github.com/onsi/gomega/types"
    12  	"k8s.io/apimachinery/pkg/util/validation/field"
    13  	"k8s.io/utils/ptr"
    14  
    15  	apisironcore "github.com/ironcore-dev/gardener-extension-provider-ironcore/pkg/apis/ironcore"
    16  )
    17  
    18  func InvalidField(fld string) types.GomegaMatcher {
    19  	return SimpleMatchField(field.ErrorTypeInvalid, fld)
    20  }
    21  
    22  func SimpleMatchField(errorType field.ErrorType, fld string) types.GomegaMatcher {
    23  	return HaveValue(MatchFields(IgnoreExtras, Fields{
    24  		"Type":  Equal(errorType),
    25  		"Field": Equal(fld),
    26  	}))
    27  }
    28  
    29  var _ = Describe("CloudProfileConfig validation", func() {
    30  	Describe("#ValidateCloudProfileConfig", func() {
    31  		var (
    32  			cloudProfileConfig  *apisironcore.CloudProfileConfig
    33  			machineImages       []core.MachineImage
    34  			nilPath             *field.Path
    35  			machineImageName    string
    36  			machineImageVersion string
    37  		)
    38  
    39  		BeforeEach(func() {
    40  			machineImageName = "ubuntu"
    41  			machineImageVersion = "1.2.3"
    42  			cloudProfileConfig = &apisironcore.CloudProfileConfig{
    43  				MachineImages: []apisironcore.MachineImages{
    44  					{
    45  						Name: machineImageName,
    46  						Versions: []apisironcore.MachineImageVersion{
    47  							{
    48  								Version:      machineImageVersion,
    49  								Image:        "registry/image:sha1234",
    50  								Architecture: ptr.To[string]("amd64"),
    51  							},
    52  						},
    53  					},
    54  				},
    55  				StorageClasses: apisironcore.StorageClasses{
    56  					Default: &apisironcore.StorageClass{
    57  						Name: "default",
    58  						Type: "defaultType",
    59  					},
    60  					Additional: []apisironcore.StorageClass{
    61  						{
    62  							Name: "foo",
    63  							Type: "fooType",
    64  						},
    65  						{
    66  							Name: "bar",
    67  							Type: "barType",
    68  						},
    69  					},
    70  				},
    71  			}
    72  			machineImages = []core.MachineImage{
    73  				{
    74  					Name: machineImageName,
    75  					Versions: []core.MachineImageVersion{
    76  						{
    77  							ExpirableVersion: core.ExpirableVersion{Version: machineImageVersion},
    78  						},
    79  					},
    80  				},
    81  			}
    82  		})
    83  
    84  		Describe("machine image validation", func() {
    85  			It("should pass validation", func() {
    86  				errorList := ValidateCloudProfileConfig(cloudProfileConfig, machineImages, nilPath)
    87  				Expect(errorList).To(BeEmpty())
    88  			})
    89  
    90  			It("should not require a machine image mapping because no versions are configured", func() {
    91  				machineImages = append(machineImages, core.MachineImage{
    92  					Name:     "suse",
    93  					Versions: nil,
    94  				})
    95  				errorList := ValidateCloudProfileConfig(cloudProfileConfig, machineImages, nilPath)
    96  				Expect(errorList).To(BeEmpty())
    97  			})
    98  
    99  			It("should require a machine image mapping to be configured", func() {
   100  				machineImages = append(machineImages, core.MachineImage{
   101  					Name: "suse",
   102  					Versions: []core.MachineImageVersion{
   103  						{
   104  							ExpirableVersion: core.ExpirableVersion{
   105  								Version: machineImageVersion,
   106  							},
   107  						},
   108  					},
   109  				})
   110  				errorList := ValidateCloudProfileConfig(cloudProfileConfig, machineImages, nilPath)
   111  				Expect(errorList).To(ConsistOf(
   112  					PointTo(MatchFields(IgnoreExtras, Fields{
   113  						"Type":  Equal(field.ErrorTypeRequired),
   114  						"Field": Equal("machineImages"),
   115  					})),
   116  				))
   117  			})
   118  
   119  			It("should forbid unsupported machine image version configuration", func() {
   120  				cloudProfileConfig.MachineImages[0].Versions[0].Image = ""
   121  				cloudProfileConfig.MachineImages[0].Versions[0].Architecture = ptr.To[string]("foo")
   122  				machineImages[0].Versions = append(machineImages[0].Versions, core.MachineImageVersion{ExpirableVersion: core.ExpirableVersion{Version: "2.0.0"}})
   123  				errorList := ValidateCloudProfileConfig(cloudProfileConfig, machineImages, nilPath)
   124  
   125  				Expect(errorList).To(ConsistOf(
   126  					PointTo(MatchFields(IgnoreExtras, Fields{
   127  						"Type":  Equal(field.ErrorTypeRequired),
   128  						"Field": Equal("machineImages[0].versions"),
   129  					})),
   130  					PointTo(MatchFields(IgnoreExtras, Fields{
   131  						"Type":  Equal(field.ErrorTypeRequired),
   132  						"Field": Equal("machineImages[0].versions[0].image"),
   133  					})),
   134  					PointTo(MatchFields(IgnoreExtras, Fields{
   135  						"Type":  Equal(field.ErrorTypeNotSupported),
   136  						"Field": Equal("machineImages[0].versions[0].architecture"),
   137  					})),
   138  				))
   139  			})
   140  		})
   141  
   142  		DescribeTable("ValidateCloudProfileConfig StorageClass name",
   143  			func(cpConfig *apisironcore.CloudProfileConfig, machineImages []core.MachineImage, fldPath *field.Path, match types.GomegaMatcher) {
   144  				errList := ValidateCloudProfileConfig(cpConfig, machineImages, fldPath)
   145  				Expect(errList).To(match)
   146  			},
   147  			Entry("invalid storageClass name in default StorageClass",
   148  				&apisironcore.CloudProfileConfig{
   149  					StorageClasses: apisironcore.StorageClasses{
   150  						Default: &apisironcore.StorageClass{
   151  							Name: "foo*",
   152  							Type: "defaultType",
   153  						},
   154  					},
   155  				},
   156  				machineImages,
   157  				nilPath,
   158  				ContainElement(InvalidField("storageClasses.defaultStorageClasses.name")),
   159  			),
   160  			Entry("invalid storageClass name in additional storageClasses",
   161  				&apisironcore.CloudProfileConfig{
   162  					StorageClasses: apisironcore.StorageClasses{
   163  						Additional: []apisironcore.StorageClass{
   164  							{
   165  								Name: "foo*",
   166  								Type: "defaultType",
   167  							},
   168  						},
   169  					},
   170  				},
   171  				machineImages,
   172  				nilPath,
   173  				ContainElement(InvalidField("storageClasses.additionalStorageClasses[0].name")),
   174  			),
   175  		)
   176  
   177  	})
   178  })