170 lines
6.3 KiB
Go
170 lines
6.3 KiB
Go
package endpoints
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
portainer "github.com/portainer/portainer/api"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// spyKubeClient implements portainer.KubeClient for testing applyKubeRegistryAccess.
|
|
// It embeds the interface so unimplemented methods panic, and overrides only the
|
|
// four methods exercised by applyKubeRegistryAccess.
|
|
type spyKubeClient struct {
|
|
portainer.KubeClient
|
|
|
|
createSecretErrors map[string]error
|
|
deleteSecretErrors map[string]error
|
|
addPullSecretErrors map[string]error
|
|
removePullSecretErrors map[string]error
|
|
|
|
createdSecrets []string
|
|
deletedSecrets []string
|
|
addedPullSecrets []string
|
|
removedPullSecrets []string
|
|
}
|
|
|
|
func newSpyKubeClient() *spyKubeClient {
|
|
return &spyKubeClient{
|
|
createSecretErrors: make(map[string]error),
|
|
deleteSecretErrors: make(map[string]error),
|
|
addPullSecretErrors: make(map[string]error),
|
|
removePullSecretErrors: make(map[string]error),
|
|
}
|
|
}
|
|
|
|
func (s *spyKubeClient) CreateRegistrySecret(_ *portainer.Registry, namespace string) error {
|
|
s.createdSecrets = append(s.createdSecrets, namespace)
|
|
return s.createSecretErrors[namespace]
|
|
}
|
|
|
|
func (s *spyKubeClient) DeleteRegistrySecret(_ portainer.RegistryID, namespace string) error {
|
|
s.deletedSecrets = append(s.deletedSecrets, namespace)
|
|
return s.deleteSecretErrors[namespace]
|
|
}
|
|
|
|
func (s *spyKubeClient) AddImagePullSecretToServiceAccount(namespace, _, _ string) error {
|
|
s.addedPullSecrets = append(s.addedPullSecrets, namespace)
|
|
return s.addPullSecretErrors[namespace]
|
|
}
|
|
|
|
func (s *spyKubeClient) RemoveImagePullSecretFromServiceAccount(namespace, _, _ string) error {
|
|
s.removedPullSecrets = append(s.removedPullSecrets, namespace)
|
|
return s.removePullSecretErrors[namespace]
|
|
}
|
|
|
|
var testRegistry = &portainer.Registry{ID: 3, URL: "registry.example.com"}
|
|
|
|
func TestApplyKubeRegistryAccess_Grant(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("single namespace granted creates secret then patches SA", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
err := applyKubeRegistryAccess(spy, testRegistry, nil, []string{"ns-a"})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []string{"ns-a"}, spy.createdSecrets)
|
|
assert.Equal(t, []string{"ns-a"}, spy.addedPullSecrets)
|
|
assert.Empty(t, spy.deletedSecrets)
|
|
assert.Empty(t, spy.removedPullSecrets)
|
|
})
|
|
|
|
t.Run("multiple namespaces granted applies to all", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
err := applyKubeRegistryAccess(spy, testRegistry, nil, []string{"ns-a", "ns-b"})
|
|
require.NoError(t, err)
|
|
assert.ElementsMatch(t, []string{"ns-a", "ns-b"}, spy.createdSecrets)
|
|
assert.ElementsMatch(t, []string{"ns-a", "ns-b"}, spy.addedPullSecrets)
|
|
})
|
|
|
|
t.Run("CreateRegistrySecret fails - AddImagePullSecret not called", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
spy.createSecretErrors["ns-a"] = errors.New("secret create failed")
|
|
err := applyKubeRegistryAccess(spy, testRegistry, nil, []string{"ns-a"})
|
|
require.Error(t, err)
|
|
assert.Equal(t, []string{"ns-a"}, spy.createdSecrets)
|
|
assert.Empty(t, spy.addedPullSecrets)
|
|
})
|
|
|
|
t.Run("AddImagePullSecret fails after secret created - returns error", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
spy.addPullSecretErrors["ns-a"] = errors.New("sa patch failed")
|
|
err := applyKubeRegistryAccess(spy, testRegistry, nil, []string{"ns-a"})
|
|
require.Error(t, err)
|
|
assert.Equal(t, []string{"ns-a"}, spy.createdSecrets)
|
|
assert.Equal(t, []string{"ns-a"}, spy.addedPullSecrets)
|
|
})
|
|
}
|
|
|
|
func TestApplyKubeRegistryAccess_Revoke(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("single namespace revoked removes from SA then deletes secret", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
err := applyKubeRegistryAccess(spy, testRegistry, []string{"ns-a"}, nil)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []string{"ns-a"}, spy.removedPullSecrets)
|
|
assert.Equal(t, []string{"ns-a"}, spy.deletedSecrets)
|
|
assert.Empty(t, spy.createdSecrets)
|
|
assert.Empty(t, spy.addedPullSecrets)
|
|
})
|
|
|
|
t.Run("multiple namespaces revoked applies to all", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
err := applyKubeRegistryAccess(spy, testRegistry, []string{"ns-a", "ns-b"}, nil)
|
|
require.NoError(t, err)
|
|
assert.ElementsMatch(t, []string{"ns-a", "ns-b"}, spy.removedPullSecrets)
|
|
assert.ElementsMatch(t, []string{"ns-a", "ns-b"}, spy.deletedSecrets)
|
|
})
|
|
|
|
t.Run("RemoveImagePullSecret fails - DeleteRegistrySecret not called", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
spy.removePullSecretErrors["ns-a"] = errors.New("sa remove failed")
|
|
err := applyKubeRegistryAccess(spy, testRegistry, []string{"ns-a"}, nil)
|
|
require.Error(t, err)
|
|
assert.Equal(t, []string{"ns-a"}, spy.removedPullSecrets)
|
|
assert.Empty(t, spy.deletedSecrets)
|
|
})
|
|
|
|
t.Run("DeleteRegistrySecret fails after SA patched - returns error", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
spy.deleteSecretErrors["ns-a"] = errors.New("secret delete failed")
|
|
err := applyKubeRegistryAccess(spy, testRegistry, []string{"ns-a"}, nil)
|
|
require.Error(t, err)
|
|
assert.Equal(t, []string{"ns-a"}, spy.removedPullSecrets)
|
|
assert.Equal(t, []string{"ns-a"}, spy.deletedSecrets)
|
|
})
|
|
}
|
|
|
|
func TestApplyKubeRegistryAccess_Mixed(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("one namespace added and one removed in same call", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
err := applyKubeRegistryAccess(spy, testRegistry, []string{"ns-old"}, []string{"ns-new"})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []string{"ns-old"}, spy.removedPullSecrets)
|
|
assert.Equal(t, []string{"ns-old"}, spy.deletedSecrets)
|
|
assert.Equal(t, []string{"ns-new"}, spy.createdSecrets)
|
|
assert.Equal(t, []string{"ns-new"}, spy.addedPullSecrets)
|
|
})
|
|
|
|
t.Run("empty old and new namespaces - no operations performed", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
err := applyKubeRegistryAccess(spy, testRegistry, nil, nil)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, spy.createdSecrets)
|
|
assert.Empty(t, spy.deletedSecrets)
|
|
assert.Empty(t, spy.addedPullSecrets)
|
|
assert.Empty(t, spy.removedPullSecrets)
|
|
})
|
|
|
|
t.Run("namespace present in both old and new - no operations performed for it", func(t *testing.T) {
|
|
spy := newSpyKubeClient()
|
|
err := applyKubeRegistryAccess(spy, testRegistry, []string{"ns-keep"}, []string{"ns-keep"})
|
|
require.NoError(t, err)
|
|
assert.Empty(t, spy.createdSecrets)
|
|
assert.Empty(t, spy.deletedSecrets)
|
|
assert.Empty(t, spy.addedPullSecrets)
|
|
assert.Empty(t, spy.removedPullSecrets)
|
|
})
|
|
}
|