airshipctl/pkg/clusterctl/implementations/reader_test.go

320 lines
7.6 KiB
Go

/*
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
https://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 implementations
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
)
func makeValidOptions() *airshipv1.Clusterctl {
return &airshipv1.Clusterctl{
Providers: []*airshipv1.Provider{
{
Name: "metal3",
Type: "InfrastructureProvider",
Versions: map[string]string{
"v0.3.1": "manifests/function/capm3/v0.3.1",
},
},
{
Name: "kubeadm",
Type: "BootstrapProvider",
Versions: map[string]string{
"v0.3.3": "manifests/function/cabpk/v0.3.3",
},
},
{
Name: "cluster-api",
Type: "InfrastructureProvider",
Versions: map[string]string{
"v0.3.3": "manifests/function/capi/v0.3.3",
},
},
{
Name: "kubeadm",
Type: "ControlPlaneProvider",
Versions: map[string]string{
"v0.3.3": "manifests/function/cacpk/v0.3.3",
},
},
},
ImageMetas: map[string]airshipv1.ImageMeta{
"all": {
Repository: "myorg.io/all-repo",
},
},
}
}
func TestNewReader(t *testing.T) {
tests := []struct {
name string
options *airshipv1.Clusterctl
}{
{
// make sure we get no panic here
name: "pass empty options",
options: &airshipv1.Clusterctl{},
},
{
name: "pass airshipctl valid config",
options: makeValidOptions(),
},
}
for _, tt := range tests {
options := tt.options
t.Run(tt.name, func(t *testing.T) {
reader, err := NewAirshipReader(options)
require.NoError(t, err)
assert.NotNil(t, reader)
})
}
}
func TestGet(t *testing.T) {
tests := []struct {
name string
options *airshipv1.Clusterctl
key string
expectedErr error
expectedResult string
}{
{
// make sure we get no panic here
name: "pass empty options",
options: &airshipv1.Clusterctl{},
key: "FOO",
expectedErr: ErrValueForVariableNotSet{Variable: "FOO"},
},
{
name: "pass airshipctl valid config",
options: makeValidOptions(),
key: "providers",
expectedErr: nil,
expectedResult: `- name: metal3
type: InfrastructureProvider
- name: kubeadm
type: BootstrapProvider
- name: cluster-api
type: InfrastructureProvider
- name: kubeadm
type: ControlPlaneProvider
`,
},
{
name: "image repo override for all clusterctl components",
options: makeValidOptions(),
key: "images",
expectedErr: nil,
expectedResult: `all:
repository: myorg.io/all-repo
`,
},
{
name: "image override for cert-manager components",
options: &airshipv1.Clusterctl{
ImageMetas: map[string]airshipv1.ImageMeta{
"cert-manager": {
Repository: "myorg.io/certmanager-repo",
Tag: "v0.1",
},
},
},
key: "images",
expectedErr: nil,
expectedResult: `cert-manager:
repository: myorg.io/certmanager-repo
tag: v0.1
`,
},
{
name: "image override for cainjector of cert-manager",
options: &airshipv1.Clusterctl{
ImageMetas: map[string]airshipv1.ImageMeta{
"cert-manager/cert-manager-cainjector": {
Repository: "myorg.io/certmanagercainjector-repo",
Tag: "v0.1",
},
},
},
key: "images",
expectedErr: nil,
expectedResult: `cert-manager/cert-manager-cainjector:
repository: myorg.io/certmanagercainjector-repo
tag: v0.1
`,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
reader, err := NewAirshipReader(tt.options)
require.NoError(t, err)
require.NotNil(t, reader)
value, err := reader.Get(tt.key)
assert.Equal(t, tt.expectedErr, err)
assert.Equal(t, tt.expectedResult, value)
})
}
}
func TestSetGet(t *testing.T) {
tests := []struct {
name string
setKey string
setGetValue string
expectedErr error
}{
{
// should return empty string
name: "set simple key",
setKey: "FOO",
expectedErr: nil,
setGetValue: "",
},
{
name: "set providers",
setKey: "providers",
expectedErr: nil,
setGetValue: `- name: metal3
type: InfrastructureProvider
- name: kubeadm
type: BootstrapProvider
- name: cluster-api
type: InfrastructureProvider
- name: kubeadm
type: ControlPlaneProvider
`,
},
{
// set empty
name: "empty key",
setKey: "",
setGetValue: "some key",
expectedErr: nil,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
reader, err := NewAirshipReader(&airshipv1.Clusterctl{})
require.NoError(t, err)
require.NotNil(t, reader)
reader.Set(tt.setKey, tt.setGetValue)
result, err := reader.Get(tt.setKey)
require.Equal(t, tt.expectedErr, err)
assert.Equal(t, tt.setGetValue, result)
})
}
}
// Test verifies that options provider returns
func TestUnmarshalProviders(t *testing.T) {
options := &airshipv1.Clusterctl{
Providers: []*airshipv1.Provider{
{
Name: config.Metal3ProviderName,
Type: string(clusterctlv1.InfrastructureProviderType),
},
{
Name: config.KubeadmBootstrapProviderName,
Type: string(clusterctlv1.BootstrapProviderType),
},
{
Name: config.ClusterAPIProviderName,
Type: string(clusterctlv1.CoreProviderType),
},
{
Name: config.KubeadmControlPlaneProviderName,
Type: string(clusterctlv1.ControlPlaneProviderType),
},
},
}
providers := []configProvider{}
reader, err := NewAirshipReader(options)
require.NoError(t, err)
require.NotNil(t, reader)
// check if we can unmarshal provider key into correct struct
err = reader.UnmarshalKey(config.ProvidersConfigKey, &providers)
require.NoError(t, err)
assert.Len(t, providers, 4)
for _, actualProvider := range providers {
assert.NotNil(t, options.Provider(actualProvider.Name, actualProvider.Type))
}
}
func TestUnmarshal(t *testing.T) {
tests := []struct {
name string
expectErr bool
variables map[string]string
getKey string
unmarshal interface{}
}{
{
name: "unmarshal into nil",
getKey: "Foo",
expectErr: true,
},
{
name: "value doesn't exist",
getKey: "Foo",
variables: map[string]string{},
unmarshal: []configProvider{},
expectErr: true,
},
{
name: "value doesn't exist",
getKey: "foo",
expectErr: false,
variables: map[string]string{
"foo": "foo: bar",
},
unmarshal: &struct {
Foo string `json:"foo,omitempty"`
}{},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
reader, err := NewAirshipReader(&airshipv1.Clusterctl{})
require.NoError(t, err)
require.NotNil(t, reader)
reader.variables = tt.variables
if tt.expectErr {
assert.Error(t, reader.UnmarshalKey(tt.getKey, tt.unmarshal))
} else {
assert.NoError(t, reader.UnmarshalKey(tt.getKey, tt.unmarshal))
}
})
}
}
// This test is simply for test coverage of the Reader interface
func TestInit(t *testing.T) {
reader, err := NewAirshipReader(&airshipv1.Clusterctl{})
require.NoError(t, err)
require.NotNil(t, reader)
assert.NoError(t, reader.Init("anything"))
}