github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/storage/driver/mock_test.go (about)

     1  /*
     2  Copyright The Helm 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 driver // import "github.com/stefanmcshane/helm/pkg/storage/driver"
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"testing"
    23  
    24  	sqlmock "github.com/DATA-DOG/go-sqlmock"
    25  	sq "github.com/Masterminds/squirrel"
    26  	"github.com/jmoiron/sqlx"
    27  
    28  	v1 "k8s.io/api/core/v1"
    29  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	kblabels "k8s.io/apimachinery/pkg/labels"
    32  	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
    33  
    34  	rspb "github.com/stefanmcshane/helm/pkg/release"
    35  )
    36  
    37  func releaseStub(name string, vers int, namespace string, status rspb.Status) *rspb.Release {
    38  	return &rspb.Release{
    39  		Name:      name,
    40  		Version:   vers,
    41  		Namespace: namespace,
    42  		Info:      &rspb.Info{Status: status},
    43  	}
    44  }
    45  
    46  func testKey(name string, vers int) string {
    47  	return fmt.Sprintf("%s.v%d", name, vers)
    48  }
    49  
    50  func tsFixtureMemory(t *testing.T) *Memory {
    51  	hs := []*rspb.Release{
    52  		// rls-a
    53  		releaseStub("rls-a", 4, "default", rspb.StatusDeployed),
    54  		releaseStub("rls-a", 1, "default", rspb.StatusSuperseded),
    55  		releaseStub("rls-a", 3, "default", rspb.StatusSuperseded),
    56  		releaseStub("rls-a", 2, "default", rspb.StatusSuperseded),
    57  		// rls-b
    58  		releaseStub("rls-b", 4, "default", rspb.StatusDeployed),
    59  		releaseStub("rls-b", 1, "default", rspb.StatusSuperseded),
    60  		releaseStub("rls-b", 3, "default", rspb.StatusSuperseded),
    61  		releaseStub("rls-b", 2, "default", rspb.StatusSuperseded),
    62  		// rls-c in other namespace
    63  		releaseStub("rls-c", 4, "mynamespace", rspb.StatusDeployed),
    64  		releaseStub("rls-c", 1, "mynamespace", rspb.StatusSuperseded),
    65  		releaseStub("rls-c", 3, "mynamespace", rspb.StatusSuperseded),
    66  		releaseStub("rls-c", 2, "mynamespace", rspb.StatusSuperseded),
    67  	}
    68  
    69  	mem := NewMemory()
    70  	for _, tt := range hs {
    71  		err := mem.Create(testKey(tt.Name, tt.Version), tt)
    72  		if err != nil {
    73  			t.Fatalf("Test setup failed to create: %s\n", err)
    74  		}
    75  	}
    76  	return mem
    77  }
    78  
    79  // newTestFixture initializes a MockConfigMapsInterface.
    80  // ConfigMaps are created for each release provided.
    81  func newTestFixtureCfgMaps(t *testing.T, releases ...*rspb.Release) *ConfigMaps {
    82  	var mock MockConfigMapsInterface
    83  	mock.Init(t, releases...)
    84  
    85  	return NewConfigMaps(&mock)
    86  }
    87  
    88  // MockConfigMapsInterface mocks a kubernetes ConfigMapsInterface
    89  type MockConfigMapsInterface struct {
    90  	corev1.ConfigMapInterface
    91  
    92  	objects map[string]*v1.ConfigMap
    93  }
    94  
    95  // Init initializes the MockConfigMapsInterface with the set of releases.
    96  func (mock *MockConfigMapsInterface) Init(t *testing.T, releases ...*rspb.Release) {
    97  	mock.objects = map[string]*v1.ConfigMap{}
    98  
    99  	for _, rls := range releases {
   100  		objkey := testKey(rls.Name, rls.Version)
   101  
   102  		cfgmap, err := newConfigMapsObject(objkey, rls, nil)
   103  		if err != nil {
   104  			t.Fatalf("Failed to create configmap: %s", err)
   105  		}
   106  		mock.objects[objkey] = cfgmap
   107  	}
   108  }
   109  
   110  // Get returns the ConfigMap by name.
   111  func (mock *MockConfigMapsInterface) Get(_ context.Context, name string, _ metav1.GetOptions) (*v1.ConfigMap, error) {
   112  	object, ok := mock.objects[name]
   113  	if !ok {
   114  		return nil, apierrors.NewNotFound(v1.Resource("tests"), name)
   115  	}
   116  	return object, nil
   117  }
   118  
   119  // List returns the a of ConfigMaps.
   120  func (mock *MockConfigMapsInterface) List(_ context.Context, opts metav1.ListOptions) (*v1.ConfigMapList, error) {
   121  	var list v1.ConfigMapList
   122  
   123  	labelSelector, err := kblabels.Parse(opts.LabelSelector)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	for _, cfgmap := range mock.objects {
   129  		if labelSelector.Matches(kblabels.Set(cfgmap.ObjectMeta.Labels)) {
   130  			list.Items = append(list.Items, *cfgmap)
   131  		}
   132  	}
   133  	return &list, nil
   134  }
   135  
   136  // Create creates a new ConfigMap.
   137  func (mock *MockConfigMapsInterface) Create(_ context.Context, cfgmap *v1.ConfigMap, _ metav1.CreateOptions) (*v1.ConfigMap, error) {
   138  	name := cfgmap.ObjectMeta.Name
   139  	if object, ok := mock.objects[name]; ok {
   140  		return object, apierrors.NewAlreadyExists(v1.Resource("tests"), name)
   141  	}
   142  	mock.objects[name] = cfgmap
   143  	return cfgmap, nil
   144  }
   145  
   146  // Update updates a ConfigMap.
   147  func (mock *MockConfigMapsInterface) Update(_ context.Context, cfgmap *v1.ConfigMap, _ metav1.UpdateOptions) (*v1.ConfigMap, error) {
   148  	name := cfgmap.ObjectMeta.Name
   149  	if _, ok := mock.objects[name]; !ok {
   150  		return nil, apierrors.NewNotFound(v1.Resource("tests"), name)
   151  	}
   152  	mock.objects[name] = cfgmap
   153  	return cfgmap, nil
   154  }
   155  
   156  // Delete deletes a ConfigMap by name.
   157  func (mock *MockConfigMapsInterface) Delete(_ context.Context, name string, _ metav1.DeleteOptions) error {
   158  	if _, ok := mock.objects[name]; !ok {
   159  		return apierrors.NewNotFound(v1.Resource("tests"), name)
   160  	}
   161  	delete(mock.objects, name)
   162  	return nil
   163  }
   164  
   165  // newTestFixture initializes a MockSecretsInterface.
   166  // Secrets are created for each release provided.
   167  func newTestFixtureSecrets(t *testing.T, releases ...*rspb.Release) *Secrets {
   168  	var mock MockSecretsInterface
   169  	mock.Init(t, releases...)
   170  
   171  	return NewSecrets(&mock)
   172  }
   173  
   174  // MockSecretsInterface mocks a kubernetes SecretsInterface
   175  type MockSecretsInterface struct {
   176  	corev1.SecretInterface
   177  
   178  	objects map[string]*v1.Secret
   179  }
   180  
   181  // Init initializes the MockSecretsInterface with the set of releases.
   182  func (mock *MockSecretsInterface) Init(t *testing.T, releases ...*rspb.Release) {
   183  	mock.objects = map[string]*v1.Secret{}
   184  
   185  	for _, rls := range releases {
   186  		objkey := testKey(rls.Name, rls.Version)
   187  
   188  		secret, err := newSecretsObject(objkey, rls, nil)
   189  		if err != nil {
   190  			t.Fatalf("Failed to create secret: %s", err)
   191  		}
   192  		mock.objects[objkey] = secret
   193  	}
   194  }
   195  
   196  // Get returns the Secret by name.
   197  func (mock *MockSecretsInterface) Get(_ context.Context, name string, _ metav1.GetOptions) (*v1.Secret, error) {
   198  	object, ok := mock.objects[name]
   199  	if !ok {
   200  		return nil, apierrors.NewNotFound(v1.Resource("tests"), name)
   201  	}
   202  	return object, nil
   203  }
   204  
   205  // List returns the a of Secret.
   206  func (mock *MockSecretsInterface) List(_ context.Context, opts metav1.ListOptions) (*v1.SecretList, error) {
   207  	var list v1.SecretList
   208  
   209  	labelSelector, err := kblabels.Parse(opts.LabelSelector)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	for _, secret := range mock.objects {
   215  		if labelSelector.Matches(kblabels.Set(secret.ObjectMeta.Labels)) {
   216  			list.Items = append(list.Items, *secret)
   217  		}
   218  	}
   219  	return &list, nil
   220  }
   221  
   222  // Create creates a new Secret.
   223  func (mock *MockSecretsInterface) Create(_ context.Context, secret *v1.Secret, _ metav1.CreateOptions) (*v1.Secret, error) {
   224  	name := secret.ObjectMeta.Name
   225  	if object, ok := mock.objects[name]; ok {
   226  		return object, apierrors.NewAlreadyExists(v1.Resource("tests"), name)
   227  	}
   228  	mock.objects[name] = secret
   229  	return secret, nil
   230  }
   231  
   232  // Update updates a Secret.
   233  func (mock *MockSecretsInterface) Update(_ context.Context, secret *v1.Secret, _ metav1.UpdateOptions) (*v1.Secret, error) {
   234  	name := secret.ObjectMeta.Name
   235  	if _, ok := mock.objects[name]; !ok {
   236  		return nil, apierrors.NewNotFound(v1.Resource("tests"), name)
   237  	}
   238  	mock.objects[name] = secret
   239  	return secret, nil
   240  }
   241  
   242  // Delete deletes a Secret by name.
   243  func (mock *MockSecretsInterface) Delete(_ context.Context, name string, _ metav1.DeleteOptions) error {
   244  	if _, ok := mock.objects[name]; !ok {
   245  		return apierrors.NewNotFound(v1.Resource("tests"), name)
   246  	}
   247  	delete(mock.objects, name)
   248  	return nil
   249  }
   250  
   251  // newTestFixtureSQL mocks the SQL database (for testing purposes)
   252  func newTestFixtureSQL(t *testing.T, releases ...*rspb.Release) (*SQL, sqlmock.Sqlmock) {
   253  	sqlDB, mock, err := sqlmock.New()
   254  	if err != nil {
   255  		t.Fatalf("error when opening stub database connection: %v", err)
   256  	}
   257  
   258  	sqlxDB := sqlx.NewDb(sqlDB, "sqlmock")
   259  	return &SQL{
   260  		db:               sqlxDB,
   261  		Log:              func(a string, b ...interface{}) {},
   262  		namespace:        "default",
   263  		statementBuilder: sq.StatementBuilder.PlaceholderFormat(sq.Dollar),
   264  	}, mock
   265  }