feat(test): add ability to store releases in multiple namespaces in the memory storage driver

this is needed to test things like listing releases in multiple namespaces

Signed-off-by: Karuppiah Natarajan <karuppiah7890@gmail.com>
pull/6684/head
Karuppiah Natarajan 6 years ago
parent e7413bd61c
commit fd89e20d55
No known key found for this signature in database
GPG Key ID: C674A28337662A96

@ -88,7 +88,7 @@ func runTestActionCmd(t *testing.T, tests []cmdTestCase) {
}
func storageFixture() *storage.Storage {
return storage.Init(driver.NewMemory())
return storage.Init(driver.NewMemory("default"))
}
func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command, string, error) {

@ -236,7 +236,7 @@ func (c *Configuration) Init(envSettings *cli.EnvSettings, allNamespaces bool, h
d.Log = log
store = storage.Init(d)
case "memory":
d := driver.NewMemory()
d := driver.NewMemory(namespace)
store = storage.Init(d)
default:
// Not sure what to do here.

@ -77,7 +77,7 @@ func actionConfigFixture(t *testing.T) *Configuration {
}
return &Configuration{
Releases: storage.Init(driver.NewMemory()),
Releases: storage.Init(driver.NewMemory("default")),
KubeClient: &kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: ioutil.Discard}},
Capabilities: chartutil.DefaultCapabilities,
RegistryClient: registryClient,

@ -179,7 +179,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
i.cfg.Capabilities = chartutil.DefaultCapabilities
i.cfg.Capabilities.APIVersions = append(i.cfg.Capabilities.APIVersions, i.APIVersions...)
i.cfg.KubeClient = &kubefake.PrintingKubeClient{Out: ioutil.Discard}
i.cfg.Releases = storage.Init(driver.NewMemory())
i.cfg.Releases = storage.Init(driver.NewMemory(i.Namespace))
} else if !i.ClientOnly && len(i.APIVersions) > 0 {
i.cfg.Log("API Version list given outside of client only mode, this list will be ignored")
}

@ -17,6 +17,7 @@ limitations under the License.
package driver
import (
"github.com/pkg/errors"
"strconv"
"strings"
"sync"
@ -29,15 +30,53 @@ var _ Driver = (*Memory)(nil)
// MemoryDriverName is the string name of this driver.
const MemoryDriverName = "Memory"
var (
// ErrNamespaceNotFound indicates that a namespace is not found.
ErrNamespaceNotFound = errors.New("namespace not found")
// ErrNamespaceAlreadyExists indicates that a namespace already exists.
ErrNamespaceAlreadyExists = errors.New("namespace already exists")
)
// Memory is the in-memory storage driver implementation.
type Memory struct {
sync.RWMutex
cache map[string]records
allNamespacesCache map[string]map[string]records
namespace string
}
// NewMemory initializes a new memory driver.
func NewMemory() *Memory {
return &Memory{cache: map[string]records{}}
func NewMemory(namespace string) *Memory {
memory := &Memory{
allNamespacesCache: map[string]map[string]records{},
namespace: namespace,
}
if namespace != "" {
_ = memory.CreateNamespace(namespace)
}
return memory
}
// SetNamespace sets the current namespace of the memory driver
func (mem *Memory) SetNamespace(namespace string) {
defer unlock(mem.wlock())
mem.namespace = namespace
}
// GetNamespace returns the current namespace of the memory driver
func (mem *Memory) GetNamespace() string {
defer unlock(mem.rlock())
return mem.namespace
}
// Namespace creates a namespace for the memory driver
func (mem *Memory) CreateNamespace(namespace string) error {
_, exists := mem.allNamespacesCache[namespace]
if exists {
return ErrNamespaceAlreadyExists
}
mem.allNamespacesCache[namespace] = make(map[string]records)
return nil
}
// Name returns the name of the driver.
@ -56,7 +95,11 @@ func (mem *Memory) Get(key string) (*rspb.Release, error) {
if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey
}
if recs, ok := mem.cache[name]; ok {
cache, exists := mem.allNamespacesCache[mem.namespace]
if !exists {
return nil, ErrNamespaceNotFound
}
if recs, ok := cache[name]; ok {
if r := recs.Get(key); r != nil {
return r.rls, nil
}
@ -72,7 +115,9 @@ func (mem *Memory) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error
defer unlock(mem.rlock())
var ls []*rspb.Release
for _, recs := range mem.cache {
for namespace, cache := range mem.allNamespacesCache {
if mem.namespace == namespace || mem.namespace == "" {
for _, recs := range cache {
recs.Iter(func(_ int, rec *record) bool {
if filter(rec.rls) {
ls = append(ls, rec.rls)
@ -80,6 +125,8 @@ func (mem *Memory) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error
return true
})
}
}
}
return ls, nil
}
@ -93,7 +140,9 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) {
lbs.fromMap(keyvals)
var ls []*rspb.Release
for _, recs := range mem.cache {
for namespace, cache := range mem.allNamespacesCache {
if mem.namespace == namespace || mem.namespace == "" {
for _, recs := range cache {
recs.Iter(func(_ int, rec *record) bool {
// A query for a release name that doesn't exist (has been deleted)
// can cause rec to be nil.
@ -106,6 +155,8 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) {
return true
})
}
}
}
return ls, nil
}
@ -113,14 +164,18 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) {
func (mem *Memory) Create(key string, rls *rspb.Release) error {
defer unlock(mem.wlock())
if recs, ok := mem.cache[rls.Name]; ok {
cache, exists := mem.allNamespacesCache[mem.namespace]
if !exists {
return ErrNamespaceNotFound
}
if recs, ok := cache[rls.Name]; ok {
if err := recs.Add(newRecord(key, rls)); err != nil {
return err
}
mem.cache[rls.Name] = recs
cache[rls.Name] = recs
return nil
}
mem.cache[rls.Name] = records{newRecord(key, rls)}
cache[rls.Name] = records{newRecord(key, rls)}
return nil
}
@ -128,7 +183,11 @@ func (mem *Memory) Create(key string, rls *rspb.Release) error {
func (mem *Memory) Update(key string, rls *rspb.Release) error {
defer unlock(mem.wlock())
if rs, ok := mem.cache[rls.Name]; ok && rs.Exists(key) {
cache, exists := mem.allNamespacesCache[mem.namespace]
if !exists {
return ErrNamespaceNotFound
}
if rs, ok := cache[rls.Name]; ok && rs.Exists(key) {
rs.Replace(key, newRecord(key, rls))
return nil
}
@ -146,14 +205,19 @@ func (mem *Memory) Delete(key string) (*rspb.Release, error) {
return nil, ErrInvalidKey
}
cache, exists := mem.allNamespacesCache[mem.namespace]
if !exists {
return nil, ErrNamespaceNotFound
}
name, ver := elems[0], elems[1]
if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey
}
if recs, ok := mem.cache[name]; ok {
if recs, ok := cache[name]; ok {
if r := recs.Remove(key); r != nil {
// recs.Remove changes the slice reference, so we have to re-assign it.
mem.cache[name] = recs
cache[name] = recs
return r.rls, nil
}
}

@ -25,7 +25,7 @@ import (
)
func TestMemoryName(t *testing.T) {
if mem := NewMemory(); mem.Name() != MemoryDriverName {
if mem := NewMemory("default"); mem.Name() != MemoryDriverName {
t.Errorf("Expected name to be %q, got %q", MemoryDriverName, mem.Name())
}
}
@ -33,23 +33,39 @@ func TestMemoryName(t *testing.T) {
func TestMemoryCreate(t *testing.T) {
var tests = []struct {
desc string
namespace string
rls *rspb.Release
err bool
}{
{
"create should success",
"create should succeed in default namespace",
"default",
releaseStub("rls-c", 1, "default", rspb.StatusDeployed),
false,
},
{
"create should fail (release already exists)",
"default",
releaseStub("rls-a", 1, "default", rspb.StatusDeployed),
true,
},
{
"create should succeed in testing namespace",
"testing",
releaseStub("rls-c", 1, "default", rspb.StatusDeployed),
false,
},
{
"create should fail (release already exists) in testing namespace",
"testing",
releaseStub("rls-c", 1, "default", rspb.StatusDeployed),
true,
},
}
ts := tsFixtureMemory(t)
for _, tt := range tests {
ts.SetNamespace(tt.namespace)
key := testKey(tt.rls.Name, tt.rls.Version)
rls := tt.rls
@ -62,17 +78,21 @@ func TestMemoryCreate(t *testing.T) {
}
func TestMemoryGet(t *testing.T) {
ts := tsFixtureMemory(t)
var tests = []struct {
desc string
namespace string
key string
err bool
}{
{"release key should exist", "rls-a.v1", false},
{"release key should not exist", "rls-a.v5", true},
{"release key should exist in default namespace", "default", "rls-a.v1", false},
{"release key should not exist in default namespace", "default", "rls-a.v5", true},
{"release key should exist in testing namespace", "testing", "rls-a.v1", false},
{"release key should not exist in testing namespace", "testing", "rls-a.v5", true},
}
ts := tsFixtureMemory(t)
for _, tt := range tests {
ts.SetNamespace(tt.namespace)
if _, err := ts.Get(tt.key); err != nil {
if !tt.err {
t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err)
@ -82,20 +102,36 @@ func TestMemoryGet(t *testing.T) {
}
func TestMemoryQuery(t *testing.T) {
ts := tsFixtureMemory(t)
var tests = []struct {
desc string
namespace string
xlen int
lbs map[string]string
}{
{
"should be 2 query results",
"should be 2 query results for default namespace",
"default",
2,
map[string]string{"status": "deployed"},
},
{
"should be 1 query result for testing namespace",
"testing",
1,
map[string]string{"status": "deployed"},
},
{
"should be 3 query results for all namespaces",
"",
3,
map[string]string{"status": "deployed"},
},
}
ts := tsFixtureMemory(t)
for _, tt := range tests {
ts.SetNamespace(tt.namespace)
l, err := ts.Query(tt.lbs)
if err != nil {
t.Fatalf("Failed to query: %s\n", err)
@ -108,28 +144,47 @@ func TestMemoryQuery(t *testing.T) {
}
func TestMemoryUpdate(t *testing.T) {
ts := tsFixtureMemory(t)
var tests = []struct {
desc string
namespace string
key string
rls *rspb.Release
err bool
}{
{
"update release status",
"update release status which exists in default namespace",
"default",
"rls-a.v4",
releaseStub("rls-a", 4, "default", rspb.StatusSuperseded),
false,
},
{
"update release status which exists in testing namespace",
"testing",
"rls-a.v1",
releaseStub("rls-a", 1, "default", rspb.StatusSuperseded),
false,
},
{
"update release does not exist",
"default",
"rls-z.v1",
releaseStub("rls-z", 1, "default", rspb.StatusUninstalled),
true,
},
{
"update release does not exist",
"testing",
"rls-z.v1",
releaseStub("rls-z", 1, "default", rspb.StatusUninstalled),
true,
},
}
ts := tsFixtureMemory(t)
for _, tt := range tests {
ts.SetNamespace(tt.namespace)
if err := ts.Update(tt.key, tt.rls); err != nil {
if !tt.err {
t.Fatalf("Failed %q: %s\n", tt.desc, err)
@ -151,20 +206,26 @@ func TestMemoryUpdate(t *testing.T) {
func TestMemoryDelete(t *testing.T) {
var tests = []struct {
desc string
namespace string
key string
err bool
}{
{"release key should exist", "rls-a.v1", false},
{"release key should not exist", "rls-a.v5", true},
{"release key should exist in default namespace", "default", "rls-a.v1", false},
{"release key should not exist in default namespace", "default", "rls-a.v5", true},
{"release key should exist in testing namespace", "testing", "rls-a.v1", false},
{"release key should not exist in testing namespace", "testing", "rls-a.v5", true},
}
ts := tsFixtureMemory(t)
// all namespaces
ts.namespace = ""
start, err := ts.Query(map[string]string{"name": "rls-a"})
if err != nil {
t.Errorf("Query failed: %s", err)
}
startLen := len(start)
for _, tt := range tests {
ts.SetNamespace(tt.namespace)
if rel, err := ts.Delete(tt.key); err != nil {
if !tt.err {
t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err)
@ -179,6 +240,8 @@ func TestMemoryDelete(t *testing.T) {
}
}
// all namespaces
ts.namespace = ""
// Make sure that the deleted records are gone.
end, err := ts.Query(map[string]string{"name": "rls-a"})
if err != nil {

@ -55,13 +55,25 @@ func tsFixtureMemory(t *testing.T) *Memory {
releaseStub("rls-b", 2, "default", rspb.StatusSuperseded),
}
mem := NewMemory()
mem := NewMemory("default")
for _, tt := range hs {
err := mem.Create(testKey(tt.Name, tt.Version), tt)
if err != nil {
t.Fatalf("Test setup failed to create: %s\n", err)
}
}
mem.namespace = "testing"
err := mem.CreateNamespace(mem.namespace)
if err != nil {
t.Fatalf("Test setup failed to create: %s\n", err)
}
anotherRls := releaseStub("rls-a", 1, "testing", rspb.StatusDeployed)
err = mem.Create(testKey(anotherRls.Name, anotherRls.Version), anotherRls)
if err != nil {
t.Fatalf("Test setup failed to create: %s\n", err)
}
return mem
}

@ -227,7 +227,7 @@ func makeKey(rlsname string, version int) string {
func Init(d driver.Driver) *Storage {
// default driver is in memory
if d == nil {
d = driver.NewMemory()
d = driver.NewMemory("default")
}
return &Storage{
Driver: d,

@ -27,7 +27,7 @@ import (
func TestStorageCreate(t *testing.T) {
// initialize storage
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
// create fake release
rls := ReleaseTestData{
@ -49,7 +49,7 @@ func TestStorageCreate(t *testing.T) {
func TestStorageUpdate(t *testing.T) {
// initialize storage
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
// create fake release
rls := ReleaseTestData{
@ -76,7 +76,7 @@ func TestStorageUpdate(t *testing.T) {
func TestStorageDelete(t *testing.T) {
// initialize storage
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
// create fake release
rls := ReleaseTestData{
@ -117,7 +117,7 @@ func TestStorageDelete(t *testing.T) {
func TestStorageList(t *testing.T) {
// initialize storage
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
// setup storage with test releases
setup := func() {
@ -166,7 +166,7 @@ func TestStorageList(t *testing.T) {
}
func TestStorageDeployed(t *testing.T) {
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
const name = "angry-bird"
const vers = 4
@ -206,7 +206,7 @@ func TestStorageDeployed(t *testing.T) {
}
func TestStorageHistory(t *testing.T) {
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
const name = "angry-bird"
@ -237,7 +237,7 @@ func TestStorageHistory(t *testing.T) {
}
func TestStorageRemoveLeastRecent(t *testing.T) {
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
storage.Log = t.Logf
// Make sure that specifying this at the outset doesn't cause any bugs.
@ -294,7 +294,7 @@ func TestStorageRemoveLeastRecent(t *testing.T) {
}
func TestStorageLast(t *testing.T) {
storage := Init(driver.NewMemory())
storage := Init(driver.NewMemory("default"))
const name = "angry-bird"

Loading…
Cancel
Save