fix(tests): Add namespace support to memory driver

Signed-off-by: Marc Khouzam <marc.khouzam@montreal.ca>
pull/7552/head
Marc Khouzam 6 years ago committed by Marc Khouzam
parent 98962dce3f
commit e6d2d10bad

@ -143,6 +143,9 @@ func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command,
root.SetOutput(buf) root.SetOutput(buf)
root.SetArgs(args) root.SetArgs(args)
if mem, ok := store.Driver.(*driver.Memory); ok {
mem.SetNamespace(settings.Namespace())
}
c, err := root.ExecuteC() c, err := root.ExecuteC()
return c, buf.String(), err return c, buf.String(), err

@ -131,6 +131,16 @@ func TestListCmd(t *testing.T) {
}, },
Chart: chartInfo, Chart: chartInfo,
}, },
{
Name: "starlord",
Version: 2,
Namespace: "milano",
Info: &release.Info{
LastDeployed: timestamp1,
Status: release.StatusDeployed,
},
Chart: chartInfo,
},
} }
tests := []cmdTestCase{{ tests := []cmdTestCase{{
@ -203,6 +213,11 @@ func TestListCmd(t *testing.T) {
cmd: "list --uninstalling", cmd: "list --uninstalling",
golden: "output/list-uninstalling.txt", golden: "output/list-uninstalling.txt",
rels: releaseFixture, rels: releaseFixture,
}, {
name: "list releases in another namespace",
cmd: "list -n milano",
golden: "output/list-namespace.txt",
rels: releaseFixture,
}} }}
runTestCmd(t, tests) runTestCmd(t, tests)
} }

@ -0,0 +1,2 @@
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
starlord milano 2 2016-01-16 00:00:01 +0000 UTC deployed chickadee-1.0.0 0.0.1

@ -241,6 +241,7 @@ func (c *Configuration) Init(getter genericclioptions.RESTClientGetter, namespac
store = storage.Init(d) store = storage.Init(d)
case "memory": case "memory":
d := driver.NewMemory() d := driver.NewMemory()
d.SetNamespace(namespace)
store = storage.Init(d) store = storage.Init(d)
default: default:
// Not sure what to do here. // Not sure what to do here.

@ -26,18 +26,33 @@ import (
var _ Driver = (*Memory)(nil) var _ Driver = (*Memory)(nil)
const (
// MemoryDriverName is the string name of this driver. // MemoryDriverName is the string name of this driver.
const MemoryDriverName = "Memory" MemoryDriverName = "Memory"
defaultNamespace = "default"
)
// A map of release names to list of release records
type memReleases map[string]records
// Memory is the in-memory storage driver implementation. // Memory is the in-memory storage driver implementation.
type Memory struct { type Memory struct {
sync.RWMutex sync.RWMutex
cache map[string]records namespace string
// A map of namespaces to releases
cache map[string]memReleases
} }
// NewMemory initializes a new memory driver. // NewMemory initializes a new memory driver.
func NewMemory() *Memory { func NewMemory() *Memory {
return &Memory{cache: map[string]records{}} return &Memory{cache: map[string]memReleases{}, namespace: "default"}
}
// SetNamespace sets a specific namespace in which releases will be accessed.
// An empty string indicates all namespaces (for the list operation)
func (mem *Memory) SetNamespace(ns string) {
mem.namespace = ns
} }
// Name returns the name of the driver. // Name returns the name of the driver.
@ -56,7 +71,7 @@ func (mem *Memory) Get(key string) (*rspb.Release, error) {
if _, err := strconv.Atoi(ver); err != nil { if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey return nil, ErrInvalidKey
} }
if recs, ok := mem.cache[name]; ok { if recs, ok := mem.cache[mem.namespace][name]; ok {
if r := recs.Get(key); r != nil { if r := recs.Get(key); r != nil {
return r.rls, nil return r.rls, nil
} }
@ -72,7 +87,12 @@ func (mem *Memory) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error
defer unlock(mem.rlock()) defer unlock(mem.rlock())
var ls []*rspb.Release var ls []*rspb.Release
for _, recs := range mem.cache { for namespace := range mem.cache {
if mem.namespace != "" {
// Should only list releases of this namespace
namespace = mem.namespace
}
for _, recs := range mem.cache[namespace] {
recs.Iter(func(_ int, rec *record) bool { recs.Iter(func(_ int, rec *record) bool {
if filter(rec.rls) { if filter(rec.rls) {
ls = append(ls, rec.rls) ls = append(ls, rec.rls)
@ -80,6 +100,11 @@ func (mem *Memory) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error
return true return true
}) })
} }
if mem.namespace != "" {
// Should only list releases of this namespace
break
}
}
return ls, nil return ls, nil
} }
@ -93,7 +118,12 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) {
lbs.fromMap(keyvals) lbs.fromMap(keyvals)
var ls []*rspb.Release var ls []*rspb.Release
for _, recs := range mem.cache { for namespace := range mem.cache {
if mem.namespace != "" {
// Should only query releases of this namespace
namespace = mem.namespace
}
for _, recs := range mem.cache[namespace] {
recs.Iter(func(_ int, rec *record) bool { recs.Iter(func(_ int, rec *record) bool {
// A query for a release name that doesn't exist (has been deleted) // A query for a release name that doesn't exist (has been deleted)
// can cause rec to be nil. // can cause rec to be nil.
@ -106,6 +136,11 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) {
return true return true
}) })
} }
if mem.namespace != "" {
// Should only query releases of this namespace
break
}
}
return ls, nil return ls, nil
} }
@ -113,14 +148,25 @@ func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) {
func (mem *Memory) Create(key string, rls *rspb.Release) error { func (mem *Memory) Create(key string, rls *rspb.Release) error {
defer unlock(mem.wlock()) defer unlock(mem.wlock())
if recs, ok := mem.cache[rls.Name]; ok { // For backwards compatibility, we protect against an unset namespace
namespace := rls.Namespace
if namespace == "" {
namespace = defaultNamespace
}
mem.SetNamespace(namespace)
if _, ok := mem.cache[namespace]; !ok {
mem.cache[namespace] = memReleases{}
}
if recs, ok := mem.cache[namespace][rls.Name]; ok {
if err := recs.Add(newRecord(key, rls)); err != nil { if err := recs.Add(newRecord(key, rls)); err != nil {
return err return err
} }
mem.cache[rls.Name] = recs mem.cache[namespace][rls.Name] = recs
return nil return nil
} }
mem.cache[rls.Name] = records{newRecord(key, rls)} mem.cache[namespace][rls.Name] = records{newRecord(key, rls)}
return nil return nil
} }
@ -128,10 +174,19 @@ func (mem *Memory) Create(key string, rls *rspb.Release) error {
func (mem *Memory) Update(key string, rls *rspb.Release) error { func (mem *Memory) Update(key string, rls *rspb.Release) error {
defer unlock(mem.wlock()) defer unlock(mem.wlock())
if rs, ok := mem.cache[rls.Name]; ok && rs.Exists(key) { // For backwards compatibility, we protect against an unset namespace
namespace := rls.Namespace
if namespace == "" {
namespace = defaultNamespace
}
mem.SetNamespace(namespace)
if _, ok := mem.cache[namespace]; ok {
if rs, ok := mem.cache[namespace][rls.Name]; ok && rs.Exists(key) {
rs.Replace(key, newRecord(key, rls)) rs.Replace(key, newRecord(key, rls))
return nil return nil
} }
}
return ErrReleaseNotFound return ErrReleaseNotFound
} }
@ -150,13 +205,15 @@ func (mem *Memory) Delete(key string) (*rspb.Release, error) {
if _, err := strconv.Atoi(ver); err != nil { if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey return nil, ErrInvalidKey
} }
if recs, ok := mem.cache[name]; ok { if _, ok := mem.cache[mem.namespace]; ok {
if recs, ok := mem.cache[mem.namespace][name]; ok {
if r := recs.Remove(key); r != nil { if r := recs.Remove(key); r != nil {
// recs.Remove changes the slice reference, so we have to re-assign it. // recs.Remove changes the slice reference, so we have to re-assign it.
mem.cache[name] = recs mem.cache[mem.namespace][name] = recs
return r.rls, nil return r.rls, nil
} }
} }
}
return nil, ErrReleaseNotFound return nil, ErrReleaseNotFound
} }

@ -37,7 +37,7 @@ func TestMemoryCreate(t *testing.T) {
err bool err bool
}{ }{
{ {
"create should success", "create should succeed",
releaseStub("rls-c", 1, "default", rspb.StatusDeployed), releaseStub("rls-c", 1, "default", rspb.StatusDeployed),
false, false,
}, },
@ -46,6 +46,16 @@ func TestMemoryCreate(t *testing.T) {
releaseStub("rls-a", 1, "default", rspb.StatusDeployed), releaseStub("rls-a", 1, "default", rspb.StatusDeployed),
true, true,
}, },
{
"create in namespace should succeed",
releaseStub("rls-a", 1, "mynamespace", rspb.StatusDeployed),
false,
},
{
"create in other namespace should fail (release already exists)",
releaseStub("rls-c", 1, "mynamespace", rspb.StatusDeployed),
true,
},
} }
ts := tsFixtureMemory(t) ts := tsFixtureMemory(t)
@ -57,6 +67,8 @@ func TestMemoryCreate(t *testing.T) {
if !tt.err { if !tt.err {
t.Fatalf("failed to create %q: %s", tt.desc, err) t.Fatalf("failed to create %q: %s", tt.desc, err)
} }
} else if tt.err {
t.Fatalf("Did not get expected error for %q\n", tt.desc)
} }
} }
} }
@ -65,18 +77,24 @@ func TestMemoryGet(t *testing.T) {
var tests = []struct { var tests = []struct {
desc string desc string
key string key string
namespace string
err bool err bool
}{ }{
{"release key should exist", "rls-a.v1", false}, {"release key should exist", "rls-a.v1", "default", false},
{"release key should not exist", "rls-a.v5", true}, {"release key should not exist", "rls-a.v5", "default", true},
{"release key in namespace should exist", "rls-c.v1", "mynamespace", false},
{"release key in namespace should not exist", "rls-a.v1", "mynamespace", true},
} }
ts := tsFixtureMemory(t) ts := tsFixtureMemory(t)
for _, tt := range tests { for _, tt := range tests {
ts.SetNamespace(tt.namespace)
if _, err := ts.Get(tt.key); err != nil { if _, err := ts.Get(tt.key); err != nil {
if !tt.err { if !tt.err {
t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err)
} }
} else if tt.err {
t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key)
} }
} }
} }
@ -125,17 +143,26 @@ func TestMemoryQuery(t *testing.T) {
var tests = []struct { var tests = []struct {
desc string desc string
xlen int xlen int
namespace string
lbs map[string]string lbs map[string]string
}{ }{
{ {
"should be 2 query results", "should be 2 query results",
2, 2,
"default",
map[string]string{"status": "deployed"},
},
{
"should be 1 query result",
1,
"mynamespace",
map[string]string{"status": "deployed"}, map[string]string{"status": "deployed"},
}, },
} }
ts := tsFixtureMemory(t) ts := tsFixtureMemory(t)
for _, tt := range tests { for _, tt := range tests {
ts.SetNamespace(tt.namespace)
l, err := ts.Query(tt.lbs) l, err := ts.Query(tt.lbs)
if err != nil { if err != nil {
t.Fatalf("Failed to query: %s\n", err) t.Fatalf("Failed to query: %s\n", err)
@ -162,8 +189,20 @@ func TestMemoryUpdate(t *testing.T) {
}, },
{ {
"update release does not exist", "update release does not exist",
"rls-z.v1", "rls-c.v1",
releaseStub("rls-z", 1, "default", rspb.StatusUninstalled), releaseStub("rls-c", 1, "default", rspb.StatusUninstalled),
true,
},
{
"update release status in namespace",
"rls-c.v4",
releaseStub("rls-c", 4, "mynamespace", rspb.StatusSuperseded),
false,
},
{
"update release in namespace does not exist",
"rls-a.v1",
releaseStub("rls-a", 1, "mynamespace", rspb.StatusUninstalled),
true, true,
}, },
} }
@ -175,8 +214,11 @@ func TestMemoryUpdate(t *testing.T) {
t.Fatalf("Failed %q: %s\n", tt.desc, err) t.Fatalf("Failed %q: %s\n", tt.desc, err)
} }
continue continue
} else if tt.err {
t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key)
} }
ts.SetNamespace(tt.rls.Namespace)
r, err := ts.Get(tt.key) r, err := ts.Get(tt.key)
if err != nil { if err != nil {
t.Fatalf("Failed to get: %s\n", err) t.Fatalf("Failed to get: %s\n", err)
@ -192,24 +234,33 @@ func TestMemoryDelete(t *testing.T) {
var tests = []struct { var tests = []struct {
desc string desc string
key string key string
namespace string
err bool err bool
}{ }{
{"release key should exist", "rls-a.v1", false}, {"release key should exist", "rls-a.v4", "default", false},
{"release key should not exist", "rls-a.v5", true}, {"release key should not exist", "rls-a.v5", "default", true},
{"release key from other namespace should not exist", "rls-c.v4", "default", true},
{"release key from namespace should exist", "rls-c.v4", "mynamespace", false},
{"release key from namespace should not exist", "rls-c.v5", "mynamespace", true},
{"release key from namespace2 should not exist", "rls-a.v4", "mynamespace", true},
} }
ts := tsFixtureMemory(t) ts := tsFixtureMemory(t)
start, err := ts.Query(map[string]string{"name": "rls-a"}) ts.SetNamespace("")
start, err := ts.Query(map[string]string{"status": "deployed"})
if err != nil { if err != nil {
t.Errorf("Query failed: %s", err) t.Errorf("Query failed: %s", err)
} }
startLen := len(start) startLen := len(start)
for _, tt := range tests { for _, tt := range tests {
ts.SetNamespace(tt.namespace)
if rel, err := ts.Delete(tt.key); err != nil { if rel, err := ts.Delete(tt.key); err != nil {
if !tt.err { if !tt.err {
t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err)
} }
continue continue
} else if tt.err {
t.Fatalf("Did not get expected error for %q '%s'\n", tt.desc, tt.key)
} else if fmt.Sprintf("%s.v%d", rel.Name, rel.Version) != tt.key { } else if fmt.Sprintf("%s.v%d", rel.Name, rel.Version) != tt.key {
t.Fatalf("Asked for delete on %s, but deleted %d", tt.key, rel.Version) t.Fatalf("Asked for delete on %s, but deleted %d", tt.key, rel.Version)
} }
@ -220,14 +271,15 @@ func TestMemoryDelete(t *testing.T) {
} }
// Make sure that the deleted records are gone. // Make sure that the deleted records are gone.
end, err := ts.Query(map[string]string{"name": "rls-a"}) ts.SetNamespace("")
end, err := ts.Query(map[string]string{"status": "deployed"})
if err != nil { if err != nil {
t.Errorf("Query failed: %s", err) t.Errorf("Query failed: %s", err)
} }
endLen := len(end) endLen := len(end)
if startLen <= endLen { if startLen-2 != endLen {
t.Errorf("expected start %d to be less than end %d", startLen, endLen) t.Errorf("expected end to be %d instead of %d", startLen-2, endLen)
for _, ee := range end { for _, ee := range end {
t.Logf("Name: %s, Version: %d", ee.Name, ee.Version) t.Logf("Name: %s, Version: %d", ee.Name, ee.Version)
} }

@ -53,6 +53,11 @@ func tsFixtureMemory(t *testing.T) *Memory {
releaseStub("rls-b", 1, "default", rspb.StatusSuperseded), releaseStub("rls-b", 1, "default", rspb.StatusSuperseded),
releaseStub("rls-b", 3, "default", rspb.StatusSuperseded), releaseStub("rls-b", 3, "default", rspb.StatusSuperseded),
releaseStub("rls-b", 2, "default", rspb.StatusSuperseded), releaseStub("rls-b", 2, "default", rspb.StatusSuperseded),
// rls-c in other namespace
releaseStub("rls-c", 4, "mynamespace", rspb.StatusDeployed),
releaseStub("rls-c", 1, "mynamespace", rspb.StatusSuperseded),
releaseStub("rls-c", 3, "mynamespace", rspb.StatusSuperseded),
releaseStub("rls-c", 2, "mynamespace", rspb.StatusSuperseded),
} }
mem := NewMemory() mem := NewMemory()

Loading…
Cancel
Save