From e25732284b88a4e0b9b66696a11b3cbadfb1c4e2 Mon Sep 17 00:00:00 2001 From: fibonacci1729 <brian@deis.com> Date: Thu, 8 Sep 2016 08:39:26 -0600 Subject: [PATCH] feat(rollback-storage): gofmt, added missing license headers, and canconical import paths --- pkg/storage/driver/cfgmaps.go | 358 ++++++++++++++--------------- pkg/storage/driver/cfgmaps_test.go | 230 +++++++++--------- pkg/storage/driver/driver.go | 38 +-- pkg/storage/driver/labels.go | 62 +++-- pkg/storage/driver/labels_test.go | 68 +++--- pkg/storage/driver/memory.go | 224 +++++++++--------- pkg/storage/driver/memory_test.go | 258 ++++++++++----------- pkg/storage/driver/records.go | 144 ++++++------ pkg/storage/driver/records_test.go | 130 ++++++----- pkg/storage/driver/testing.go | 166 +++++++------ pkg/storage/filter.go | 2 +- pkg/storage/storage.go | 102 ++++---- pkg/storage/storage_test.go | 316 ++++++++++++------------- 13 files changed, 1089 insertions(+), 1009 deletions(-) diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 64521a411..30b716b6c 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -17,20 +17,20 @@ limitations under the License. package driver // import "k8s.io/helm/pkg/storage/driver" import ( - "encoding/base64" - "fmt" - "log" - "strconv" - "time" + "encoding/base64" + "fmt" + "log" + "strconv" + "time" - "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/proto" - rspb "k8s.io/helm/pkg/proto/hapi/release" + rspb "k8s.io/helm/pkg/proto/hapi/release" - "k8s.io/kubernetes/pkg/api" - kberrs "k8s.io/kubernetes/pkg/api/errors" - client "k8s.io/kubernetes/pkg/client/unversioned" - kblabels "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/api" + kberrs "k8s.io/kubernetes/pkg/api/errors" + client "k8s.io/kubernetes/pkg/client/unversioned" + kblabels "k8s.io/kubernetes/pkg/labels" ) var _ Driver = (*ConfigMaps)(nil) @@ -43,169 +43,169 @@ var b64 = base64.StdEncoding // ConfigMaps is a wrapper around an implementation of a kubernetes // ConfigMapsInterface. type ConfigMaps struct { - impl client.ConfigMapsInterface + impl client.ConfigMapsInterface } // NewConfigMaps initializes a new ConfigMaps wrapping an implmenetation of // the kubernetes ConfigMapsInterface. func NewConfigMaps(impl client.ConfigMapsInterface) *ConfigMaps { - return &ConfigMaps{impl: impl} + return &ConfigMaps{impl: impl} } // Name returns the name of the driver. func (cfgmaps *ConfigMaps) Name() string { - return ConfigMapsDriverName + return ConfigMapsDriverName } // Get fetches the release named by key. The corresponding release is returned // or error if not found. func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) { - // fetch the configmap holding the release named by key - obj, err := cfgmaps.impl.Get(key) - if err != nil { - if kberrs.IsNotFound(err) { - return nil, ErrReleaseNotFound - } - - logerrf(err, "get: failed to get %q", key) - return nil, err - } - // found the configmap, decode the base64 data string - r, err := decodeRelease(obj.Data["release"]) - if err != nil { - logerrf(err, "get: failed to decode data %q", key) - return nil, err - } - // return the release object - return r, nil + // fetch the configmap holding the release named by key + obj, err := cfgmaps.impl.Get(key) + if err != nil { + if kberrs.IsNotFound(err) { + return nil, ErrReleaseNotFound + } + + logerrf(err, "get: failed to get %q", key) + return nil, err + } + // found the configmap, decode the base64 data string + r, err := decodeRelease(obj.Data["release"]) + if err != nil { + logerrf(err, "get: failed to decode data %q", key) + return nil, err + } + // return the release object + return r, nil } // List fetches all releases and returns the list releases such // that filter(release) == true. An error is returned if the // configmap fails to retrieve the releases. func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) { - list, err := cfgmaps.impl.List(api.ListOptions{}) - if err != nil { - logerrf(err, "list: failed to list") - return nil, err - } - - var results []*rspb.Release - - // iterate over the configmaps object list - // and decode each release - for _, item := range list.Items { - rls, err := decodeRelease(item.Data["release"]) - if err != nil { - logerrf(err, "list: failed to decode release: %s", rls) - continue - } - if filter(rls) { - results = append(results, rls) - } - } - return results, nil + list, err := cfgmaps.impl.List(api.ListOptions{}) + if err != nil { + logerrf(err, "list: failed to list") + return nil, err + } + + var results []*rspb.Release + + // iterate over the configmaps object list + // and decode each release + for _, item := range list.Items { + rls, err := decodeRelease(item.Data["release"]) + if err != nil { + logerrf(err, "list: failed to decode release: %s", rls) + continue + } + if filter(rls) { + results = append(results, rls) + } + } + return results, nil } // Query fetches all releases that match the provided map of labels. // An error is returned if the configmap fails to retrieve the releases. func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, error) { - ls := kblabels.Set{} - for k, v := range labels { - ls[k] = v - } - - opts := api.ListOptions{LabelSelector: ls.AsSelector()} - - list, err := cfgmaps.impl.List(opts) - if err != nil { - logerrf(err, "query: failed to query with labels") - return nil, err - } - - if len(list.Items) == 0 { - return nil, ErrReleaseNotFound - } - - var results []*rspb.Release - for _, item := range list.Items { - rls, err := decodeRelease(item.Data["release"]) - if err != nil { - logerrf(err, "query: failed to decode release: %s", err) - continue - } - results = append(results, rls) - } - return results, nil + ls := kblabels.Set{} + for k, v := range labels { + ls[k] = v + } + + opts := api.ListOptions{LabelSelector: ls.AsSelector()} + + list, err := cfgmaps.impl.List(opts) + if err != nil { + logerrf(err, "query: failed to query with labels") + return nil, err + } + + if len(list.Items) == 0 { + return nil, ErrReleaseNotFound + } + + var results []*rspb.Release + for _, item := range list.Items { + rls, err := decodeRelease(item.Data["release"]) + if err != nil { + logerrf(err, "query: failed to decode release: %s", err) + continue + } + results = append(results, rls) + } + return results, nil } // Create creates a new ConfigMap holding the release. If the // ConfigMap already exists, ErrReleaseExists is returned. func (cfgmaps *ConfigMaps) Create(key string, rls *rspb.Release) error { - // set labels for configmaps object meta data - var lbs labels - - lbs.init() - lbs.set("CREATED_AT", strconv.Itoa(int(time.Now().Unix()))) - - // create a new configmap to hold the release - obj, err := newConfigMapsObject(key, rls, lbs) - if err != nil { - logerrf(err, "create: failed to encode release %q", rls.Name) - return err - } - // push the configmap object out into the kubiverse - if _, err := cfgmaps.impl.Create(obj); err != nil { - if kberrs.IsAlreadyExists(err) { - return ErrReleaseExists - } - - logerrf(err, "create: failed to create") - return err - } - return nil + // set labels for configmaps object meta data + var lbs labels + + lbs.init() + lbs.set("CREATED_AT", strconv.Itoa(int(time.Now().Unix()))) + + // create a new configmap to hold the release + obj, err := newConfigMapsObject(key, rls, lbs) + if err != nil { + logerrf(err, "create: failed to encode release %q", rls.Name) + return err + } + // push the configmap object out into the kubiverse + if _, err := cfgmaps.impl.Create(obj); err != nil { + if kberrs.IsAlreadyExists(err) { + return ErrReleaseExists + } + + logerrf(err, "create: failed to create") + return err + } + return nil } // Update updates the ConfigMap holding the release. If not found // the ConfigMap is created to hold the release. func (cfgmaps *ConfigMaps) Update(key string, rls *rspb.Release) error { - // set labels for configmaps object meta data - var lbs labels - - lbs.init() - lbs.set("MODIFIED_AT", strconv.Itoa(int(time.Now().Unix()))) - - // create a new configmap object to hold the release - obj, err := newConfigMapsObject(key, rls, lbs) - if err != nil { - logerrf(err, "update: failed to encode release %q", rls.Name) - return err - } - // push the configmap object out into the kubiverse - _, err = cfgmaps.impl.Update(obj) - if err != nil { - logerrf(err, "update: failed to update") - return err - } - return nil + // set labels for configmaps object meta data + var lbs labels + + lbs.init() + lbs.set("MODIFIED_AT", strconv.Itoa(int(time.Now().Unix()))) + + // create a new configmap object to hold the release + obj, err := newConfigMapsObject(key, rls, lbs) + if err != nil { + logerrf(err, "update: failed to encode release %q", rls.Name) + return err + } + // push the configmap object out into the kubiverse + _, err = cfgmaps.impl.Update(obj) + if err != nil { + logerrf(err, "update: failed to update") + return err + } + return nil } // Delete deletes the ConfigMap holding the release named by key. func (cfgmaps *ConfigMaps) Delete(key string) (rls *rspb.Release, err error) { - // fetch the release to check existence - if rls, err = cfgmaps.Get(key); err != nil { - if kberrs.IsNotFound(err) { - return nil, ErrReleaseNotFound - } - - logerrf(err, "delete: failed to get release %q", rls.Name) - return nil, err - } - // delete the release - if err = cfgmaps.impl.Delete(key); err != nil { - return rls, err - } - return rls, nil + // fetch the release to check existence + if rls, err = cfgmaps.Get(key); err != nil { + if kberrs.IsNotFound(err) { + return nil, ErrReleaseNotFound + } + + logerrf(err, "delete: failed to get release %q", rls.Name) + return nil, err + } + // delete the release + if err = cfgmaps.impl.Delete(key); err != nil { + return rls, err + } + return rls, nil } // newConfigMapsObject constructs a kubernetes ConfigMap object @@ -222,42 +222,42 @@ func (cfgmaps *ConfigMaps) Delete(key string) (rls *rspb.Release, err error) { // "NAME" - name of the release. // func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*api.ConfigMap, error) { - const owner = "TILLER" - - // encode the release - s, err := encodeRelease(rls) - if err != nil { - return nil, err - } - - if lbs == nil { - lbs.init() - } - - // apply labels - lbs.set("NAME", rls.Name) - lbs.set("OWNER", owner) - lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)]) - lbs.set("VERSION", strconv.Itoa(int(rls.Version))) - - // create and return configmap object - return &api.ConfigMap{ - ObjectMeta: api.ObjectMeta{ - Name: key, - Labels: lbs.toMap(), - }, - Data: map[string]string{"release": s}, - }, nil + const owner = "TILLER" + + // encode the release + s, err := encodeRelease(rls) + if err != nil { + return nil, err + } + + if lbs == nil { + lbs.init() + } + + // apply labels + lbs.set("NAME", rls.Name) + lbs.set("OWNER", owner) + lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)]) + lbs.set("VERSION", strconv.Itoa(int(rls.Version))) + + // create and return configmap object + return &api.ConfigMap{ + ObjectMeta: api.ObjectMeta{ + Name: key, + Labels: lbs.toMap(), + }, + Data: map[string]string{"release": s}, + }, nil } // encodeRelease encodes a release returning a base64 encoded // binary protobuf encoding representation, or error. func encodeRelease(rls *rspb.Release) (string, error) { - b, err := proto.Marshal(rls) - if err != nil { - return "", err - } - return b64.EncodeToString(b), nil + b, err := proto.Marshal(rls) + if err != nil { + return "", err + } + return b64.EncodeToString(b), nil } // decodeRelease decodes the bytes in data into a release @@ -265,21 +265,21 @@ func encodeRelease(rls *rspb.Release) (string, error) { // valid protobuf encoding of a release, otherwise // an error is returned. func decodeRelease(data string) (*rspb.Release, error) { - // base64 decode string - b, err := b64.DecodeString(data) - if err != nil { - return nil, err - } - - var rls rspb.Release - // unmarshal protobuf bytes - if err := proto.Unmarshal(b, &rls); err != nil { - return nil, err - } - return &rls, nil + // base64 decode string + b, err := b64.DecodeString(data) + if err != nil { + return nil, err + } + + var rls rspb.Release + // unmarshal protobuf bytes + if err := proto.Unmarshal(b, &rls); err != nil { + return nil, err + } + return &rls, nil } // logerrf wraps an error with the a formatted string (used for debugging) func logerrf(err error, format string, args ...interface{}) { - log.Printf("configmaps: %s: %s\n", fmt.Sprintf(format, args...), err) + log.Printf("configmaps: %s: %s\n", fmt.Sprintf(format, args...), err) } diff --git a/pkg/storage/driver/cfgmaps_test.go b/pkg/storage/driver/cfgmaps_test.go index 7baa066bd..f89e26b36 100644 --- a/pkg/storage/driver/cfgmaps_test.go +++ b/pkg/storage/driver/cfgmaps_test.go @@ -14,134 +14,134 @@ limitations under the License. package driver import ( - "reflect" - "testing" + "reflect" + "testing" - rspb "k8s.io/helm/pkg/proto/hapi/release" + rspb "k8s.io/helm/pkg/proto/hapi/release" ) func TestConfigMapName(t *testing.T) { - c := newTestFixtureCfgMaps(t) - if c.Name() != ConfigMapsDriverName { - t.Errorf("Expected name to be %q, got %q", ConfigMapsDriverName, c.Name()) - } + c := newTestFixtureCfgMaps(t) + if c.Name() != ConfigMapsDriverName { + t.Errorf("Expected name to be %q, got %q", ConfigMapsDriverName, c.Name()) + } } func TestConfigMapGet(t *testing.T) { - vers := int32(1) - name := "smug-pigeon" - key := testKey(name, vers) - rel := releaseStub(name, vers, rspb.Status_DEPLOYED) - - cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{rel}...) - - // get release with key - got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release: %s", err) - } - // compare fetched release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%q}, got {%q}", rel, got) - } + vers := int32(1) + name := "smug-pigeon" + key := testKey(name, vers) + rel := releaseStub(name, vers, rspb.Status_DEPLOYED) + + cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{rel}...) + + // get release with key + got, err := cfgmaps.Get(key) + if err != nil { + t.Fatalf("Failed to get release: %s", err) + } + // compare fetched release with original + if !reflect.DeepEqual(rel, got) { + t.Errorf("Expected {%q}, got {%q}", rel, got) + } } func TestConfigMapList(t *testing.T) { - cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{ - releaseStub("key-1", 1, rspb.Status_DELETED), - releaseStub("key-2", 1, rspb.Status_DELETED), - releaseStub("key-3", 1, rspb.Status_DEPLOYED), - releaseStub("key-4", 1, rspb.Status_DEPLOYED), - releaseStub("key-5", 1, rspb.Status_SUPERSEDED), - releaseStub("key-6", 1, rspb.Status_SUPERSEDED), - }...) - - // list all deleted releases - del, err := cfgmaps.List(func(rel *rspb.Release) bool { - return rel.Info.Status.Code == rspb.Status_DELETED - }) - // check - if err != nil { - t.Errorf("Failed to list deleted: %s", err) - } - if len(del) != 2 { - t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) - } - - // list all deployed releases - dpl, err := cfgmaps.List(func(rel *rspb.Release) bool { - return rel.Info.Status.Code == rspb.Status_DEPLOYED - }) - // check - if err != nil { - t.Errorf("Failed to list deployed: %s", err) - } - if len(dpl) != 2 { - t.Errorf("Expected 2 deployed, got %d", len(dpl)) - } - - // list all superseded releases - ssd, err := cfgmaps.List(func(rel *rspb.Release) bool { - return rel.Info.Status.Code == rspb.Status_SUPERSEDED - }) - // check - if err != nil { - t.Errorf("Failed to list superseded: %s", err) - } - if len(ssd) != 2 { - t.Errorf("Expected 2 superseded, got %d", len(ssd)) - } + cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{ + releaseStub("key-1", 1, rspb.Status_DELETED), + releaseStub("key-2", 1, rspb.Status_DELETED), + releaseStub("key-3", 1, rspb.Status_DEPLOYED), + releaseStub("key-4", 1, rspb.Status_DEPLOYED), + releaseStub("key-5", 1, rspb.Status_SUPERSEDED), + releaseStub("key-6", 1, rspb.Status_SUPERSEDED), + }...) + + // list all deleted releases + del, err := cfgmaps.List(func(rel *rspb.Release) bool { + return rel.Info.Status.Code == rspb.Status_DELETED + }) + // check + if err != nil { + t.Errorf("Failed to list deleted: %s", err) + } + if len(del) != 2 { + t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del) + } + + // list all deployed releases + dpl, err := cfgmaps.List(func(rel *rspb.Release) bool { + return rel.Info.Status.Code == rspb.Status_DEPLOYED + }) + // check + if err != nil { + t.Errorf("Failed to list deployed: %s", err) + } + if len(dpl) != 2 { + t.Errorf("Expected 2 deployed, got %d", len(dpl)) + } + + // list all superseded releases + ssd, err := cfgmaps.List(func(rel *rspb.Release) bool { + return rel.Info.Status.Code == rspb.Status_SUPERSEDED + }) + // check + if err != nil { + t.Errorf("Failed to list superseded: %s", err) + } + if len(ssd) != 2 { + t.Errorf("Expected 2 superseded, got %d", len(ssd)) + } } func TestConfigMapCreate(t *testing.T) { - cfgmaps := newTestFixtureCfgMaps(t) - - vers := int32(1) - name := "smug-pigeon" - key := testKey(name, vers) - rel := releaseStub(name, vers, rspb.Status_DEPLOYED) - - // store the release in a configmap - if err := cfgmaps.Create(key, rel); err != nil { - t.Fatalf("Failed to create release with key %q: %s", key, err) - } - - // get the release back - got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } - - // compare created release with original - if !reflect.DeepEqual(rel, got) { - t.Errorf("Expected {%q}, got {%q}", rel, got) - } + cfgmaps := newTestFixtureCfgMaps(t) + + vers := int32(1) + name := "smug-pigeon" + key := testKey(name, vers) + rel := releaseStub(name, vers, rspb.Status_DEPLOYED) + + // store the release in a configmap + if err := cfgmaps.Create(key, rel); err != nil { + t.Fatalf("Failed to create release with key %q: %s", key, err) + } + + // get the release back + got, err := cfgmaps.Get(key) + if err != nil { + t.Fatalf("Failed to get release with key %q: %s", key, err) + } + + // compare created release with original + if !reflect.DeepEqual(rel, got) { + t.Errorf("Expected {%q}, got {%q}", rel, got) + } } func TestConfigMapUpdate(t *testing.T) { - vers := int32(1) - name := "smug-pigeon" - key := testKey(name, vers) - rel := releaseStub(name, vers, rspb.Status_DEPLOYED) - - cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{rel}...) - - // modify release status code - rel.Info.Status.Code = rspb.Status_SUPERSEDED - - // perform the update - if err := cfgmaps.Update(key, rel); err != nil { - t.Fatalf("Failed to update release: %s", err) - } - - // fetch the updated release - got, err := cfgmaps.Get(key) - if err != nil { - t.Fatalf("Failed to get release with key %q: %s", key, err) - } - - // check release has actually been updated by comparing modified fields - if rel.Info.Status.Code != got.Info.Status.Code { - t.Errorf("Expected status %s, got status %s", rel.Info.Status.Code, got.Info.Status.Code) - } -} \ No newline at end of file + vers := int32(1) + name := "smug-pigeon" + key := testKey(name, vers) + rel := releaseStub(name, vers, rspb.Status_DEPLOYED) + + cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{rel}...) + + // modify release status code + rel.Info.Status.Code = rspb.Status_SUPERSEDED + + // perform the update + if err := cfgmaps.Update(key, rel); err != nil { + t.Fatalf("Failed to update release: %s", err) + } + + // fetch the updated release + got, err := cfgmaps.Get(key) + if err != nil { + t.Fatalf("Failed to get release with key %q: %s", key, err) + } + + // check release has actually been updated by comparing modified fields + if rel.Info.Status.Code != got.Info.Status.Code { + t.Errorf("Expected status %s, got status %s", rel.Info.Status.Code, got.Info.Status.Code) + } +} diff --git a/pkg/storage/driver/driver.go b/pkg/storage/driver/driver.go index 4024012ee..45b442cd7 100644 --- a/pkg/storage/driver/driver.go +++ b/pkg/storage/driver/driver.go @@ -17,18 +17,18 @@ limitations under the License. package driver // import "k8s.io/helm/pkg/storage/driver" import ( - "errors" + "errors" - rspb "k8s.io/helm/pkg/proto/hapi/release" + rspb "k8s.io/helm/pkg/proto/hapi/release" ) var ( - // ErrReleaseNotFound indicates that a release is not found. - ErrReleaseNotFound = errors.New("release: not found") - // ErrReleaseExists indicates that a release already exists. - ErrReleaseExists = errors.New("release: already exists") - // ErrInvalidKey indicates that a release key could not be parsed. - ErrInvalidKey = errors.New("release: invalid key") + // ErrReleaseNotFound indicates that a release is not found. + ErrReleaseNotFound = errors.New("release: not found") + // ErrReleaseExists indicates that a release already exists. + ErrReleaseExists = errors.New("release: already exists") + // ErrInvalidKey indicates that a release key could not be parsed. + ErrInvalidKey = errors.New("release: invalid key") ) // Creator is the interface that wraps the Create method. @@ -36,7 +36,7 @@ var ( // Create stores the release or returns ErrReleaseExists // if an identical release already exists. type Creator interface { - Create(key string, rls *rspb.Release) error + Create(key string, rls *rspb.Release) error } // Updator is the interface that wraps the Update method. @@ -44,7 +44,7 @@ type Creator interface { // Update updates an existing release or returns // ErrReleaseNotFound if the release does not exist. type Updator interface { - Update(key string, rls *rspb.Release) error + Update(key string, rls *rspb.Release) error } // Deletor is the interface that wraps the Delete method. @@ -52,7 +52,7 @@ type Updator interface { // Delete deletes the release named by key or returns // ErrReleaseNotFound if the release does not exist. type Deletor interface { - Delete(key string) (*rspb.Release, error) + Delete(key string) (*rspb.Release, error) } // Queryor is the interface that wraps the Get and List methods. @@ -64,9 +64,9 @@ type Deletor interface { // // Query returns the set of all releases that match the provided label set. type Queryor interface { - Get(key string) (*rspb.Release, error) - List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) - Query(labels map[string]string) ([]*rspb.Release, error) + Get(key string) (*rspb.Release, error) + List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) + Query(labels map[string]string) ([]*rspb.Release, error) } // Driver is the interface composed of Creator, Updator, Deletor, Queryor @@ -74,9 +74,9 @@ type Queryor interface { // and retrieving tiller releases from some underlying storage mechanism, // e.g. memory, configmaps. type Driver interface { - Creator - Updator - Deletor - Queryor - Name() string + Creator + Updator + Deletor + Queryor + Name() string } diff --git a/pkg/storage/driver/labels.go b/pkg/storage/driver/labels.go index f26dba7ab..23538d214 100644 --- a/pkg/storage/driver/labels.go +++ b/pkg/storage/driver/labels.go @@ -1,9 +1,25 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 + + http://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 driver import ( - "bytes" - "fmt" - "io" + "bytes" + "fmt" + "io" ) // labels is a map of key value pairs to be included as metadata in a configmap object. @@ -14,37 +30,37 @@ func (lbs labels) get(key string) string { return lbs[key] } func (lbs labels) set(key, val string) { lbs[key] = val } func (lbs labels) keys() (ls []string) { - for key := range lbs { - ls = append(ls, key) - } - return + for key := range lbs { + ls = append(ls, key) + } + return } func (lbs labels) match(set labels) bool { - for _, key := range set.keys() { - if lbs.get(key) != set.get(key) { - return false - } - } - return true + for _, key := range set.keys() { + if lbs.get(key) != set.get(key) { + return false + } + } + return true } func (lbs labels) toMap() map[string]string { return lbs } func (lbs *labels) fromMap(kvs map[string]string) { - for k, v := range kvs { - lbs.set(k, v) - } + for k, v := range kvs { + lbs.set(k, v) + } } func (lbs labels) dump(w io.Writer) error { - var b bytes.Buffer + var b bytes.Buffer - fmt.Fprintln(&b, "labels:") - for k, v := range lbs { - fmt.Fprintf(&b, "\t- %q -> %q\n", k, v) - } + fmt.Fprintln(&b, "labels:") + for k, v := range lbs { + fmt.Fprintf(&b, "\t- %q -> %q\n", k, v) + } - _, err := w.Write(b.Bytes()) - return err + _, err := w.Write(b.Bytes()) + return err } diff --git a/pkg/storage/driver/labels_test.go b/pkg/storage/driver/labels_test.go index c9f44fba2..af0bd24e5 100644 --- a/pkg/storage/driver/labels_test.go +++ b/pkg/storage/driver/labels_test.go @@ -1,33 +1,49 @@ -package driver +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 + + http://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 driver // import "k8s.io/helm/pkg/storage/driver" import ( - "testing" + "testing" ) func TestLabelsMatch(t *testing.T) { - var tests = []struct { - desc string - set1 labels - set2 labels - expect bool - }{ - { - "equal labels sets", - labels(map[string]string{"KEY_A": "VAL_A", "KEY_B": "VAL_B"}), - labels(map[string]string{"KEY_A": "VAL_A", "KEY_B": "VAL_B"}), - true, - }, - { - "disjoint label sets", - labels(map[string]string{"KEY_C": "VAL_C", "KEY_D": "VAL_D"}), - labels(map[string]string{"KEY_A": "VAL_A", "KEY_B": "VAL_B"}), - false, - }, - } + var tests = []struct { + desc string + set1 labels + set2 labels + expect bool + }{ + { + "equal labels sets", + labels(map[string]string{"KEY_A": "VAL_A", "KEY_B": "VAL_B"}), + labels(map[string]string{"KEY_A": "VAL_A", "KEY_B": "VAL_B"}), + true, + }, + { + "disjoint label sets", + labels(map[string]string{"KEY_C": "VAL_C", "KEY_D": "VAL_D"}), + labels(map[string]string{"KEY_A": "VAL_A", "KEY_B": "VAL_B"}), + false, + }, + } - for _, tt := range tests { - if !tt.set1.match(tt.set2) && tt.expect { - t.Fatalf("Expected match '%s'\n", tt.desc) - } - } + for _, tt := range tests { + if !tt.set1.match(tt.set2) && tt.expect { + t.Fatalf("Expected match '%s'\n", tt.desc) + } + } } diff --git a/pkg/storage/driver/memory.go b/pkg/storage/driver/memory.go index 6513609fe..9dafcf5b1 100644 --- a/pkg/storage/driver/memory.go +++ b/pkg/storage/driver/memory.go @@ -17,14 +17,14 @@ limitations under the License. package driver import ( - "bytes" - "fmt" - "io" - "strconv" - "strings" - "sync" - - rspb "k8s.io/helm/pkg/proto/hapi/release" + "bytes" + "fmt" + "io" + "strconv" + "strings" + "sync" + + rspb "k8s.io/helm/pkg/proto/hapi/release" ) var _ Driver = (*Memory)(nil) @@ -34,158 +34,158 @@ const MemoryDriverName = "Memory" // Memory is the in-memory storage driver implementation. type Memory struct { - sync.RWMutex - cache map[string]records + sync.RWMutex + cache map[string]records } // NewMemory initializes a new memory driver. func NewMemory() *Memory { - return &Memory{cache: map[string]records{}} + return &Memory{cache: map[string]records{}} } // Name returns the name of the driver. func (mem *Memory) Name() string { - return MemoryDriverName + return MemoryDriverName } // Get returns the release named by key or returns ErrReleaseNotFound. func (mem *Memory) Get(key string) (*rspb.Release, error) { - defer unlock(mem.rlock()) - - switch elems := strings.Split(key, ".v"); len(elems) { - case 2: - name, ver := elems[0], elems[1] - if _, err := strconv.Atoi(ver); err != nil { - return nil, ErrInvalidKey - } - if recs, ok := mem.cache[name]; ok { - if r := recs.Get(key); r != nil { - return r.rls, nil - } - } - return nil, ErrReleaseNotFound - default: - return nil, ErrInvalidKey - } + defer unlock(mem.rlock()) + + switch elems := strings.Split(key, ".v"); len(elems) { + case 2: + name, ver := elems[0], elems[1] + if _, err := strconv.Atoi(ver); err != nil { + return nil, ErrInvalidKey + } + if recs, ok := mem.cache[name]; ok { + if r := recs.Get(key); r != nil { + return r.rls, nil + } + } + return nil, ErrReleaseNotFound + default: + return nil, ErrInvalidKey + } } // List returns the list of all releases such that filter(release) == true 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 { - recs.Iter(func(_ int, rec *record) bool { - if filter(rec.rls) { - ls = append(ls, rec.rls) - } - return true - }) - } - return ls, nil + defer unlock(mem.rlock()) + + var ls []*rspb.Release + for _, recs := range mem.cache { + recs.Iter(func(_ int, rec *record) bool { + if filter(rec.rls) { + ls = append(ls, rec.rls) + } + return true + }) + } + return ls, nil } // Query returns the set of releases that match the provided set of labels func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) { - defer unlock(mem.rlock()) - - var lbs labels - - lbs.init() - lbs.fromMap(keyvals) - - var ls []*rspb.Release - for _, recs := range mem.cache { - recs.Iter(func(_ int, rec *record) bool { - if rec.lbs.match(lbs) { - ls = append(ls, rec.rls) - } - return true - }) - } - return ls, nil + defer unlock(mem.rlock()) + + var lbs labels + + lbs.init() + lbs.fromMap(keyvals) + + var ls []*rspb.Release + for _, recs := range mem.cache { + recs.Iter(func(_ int, rec *record) bool { + if rec.lbs.match(lbs) { + ls = append(ls, rec.rls) + } + return true + }) + } + return ls, nil } // Create creates a new release or returns ErrReleaseExists. func (mem *Memory) Create(key string, rls *rspb.Release) error { - defer unlock(mem.wlock()) - - if recs, ok := mem.cache[rls.Name]; ok { - if err := recs.Add(newRecord(key, rls)); err != nil { - return err - } - mem.cache[rls.Name] = recs - return nil - } - mem.cache[rls.Name] = records{newRecord(key, rls)} - return nil + defer unlock(mem.wlock()) + + if recs, ok := mem.cache[rls.Name]; ok { + if err := recs.Add(newRecord(key, rls)); err != nil { + return err + } + mem.cache[rls.Name] = recs + return nil + } + mem.cache[rls.Name] = records{newRecord(key, rls)} + return nil } // Update updates a release or returns ErrReleaseNotFound. 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) { - rs.Replace(key, newRecord(key, rls)) - return nil - } - return ErrReleaseNotFound + if rs, ok := mem.cache[rls.Name]; ok && rs.Exists(key) { + rs.Replace(key, newRecord(key, rls)) + return nil + } + return ErrReleaseNotFound } // Delete deletes a release or returns ErrReleaseNotFound. func (mem *Memory) Delete(key string) (*rspb.Release, error) { - defer unlock(mem.wlock()) - - switch elems := strings.Split(key, ".v"); len(elems) { - case 2: - name, ver := elems[0], elems[1] - if _, err := strconv.Atoi(ver); err != nil { - return nil, ErrInvalidKey - } - if recs, ok := mem.cache[name]; ok { - if r := recs.Remove(key); r != nil { - return r.rls, nil - } - } - return nil, ErrReleaseNotFound - default: - return nil, ErrInvalidKey - } - return nil, ErrReleaseNotFound + defer unlock(mem.wlock()) + + switch elems := strings.Split(key, ".v"); len(elems) { + case 2: + name, ver := elems[0], elems[1] + if _, err := strconv.Atoi(ver); err != nil { + return nil, ErrInvalidKey + } + if recs, ok := mem.cache[name]; ok { + if r := recs.Remove(key); r != nil { + return r.rls, nil + } + } + return nil, ErrReleaseNotFound + default: + return nil, ErrInvalidKey + } + return nil, ErrReleaseNotFound } func (mem *Memory) dump(w io.Writer) error { - var b bytes.Buffer + var b bytes.Buffer - fmt.Fprintln(&b, "memory:") - for key, recs := range mem.cache { - fmt.Fprintf(&b, "\t# %q\n", key) + fmt.Fprintln(&b, "memory:") + for key, recs := range mem.cache { + fmt.Fprintf(&b, "\t# %q\n", key) - recs.Iter(func(index int, r *record) bool { - fmt.Fprintf(&b, "\t\t- [%d] v%d (status = %s)\n", - index, - r.rls.Version, - r.rls.Info.Status.Code, - ) + recs.Iter(func(index int, r *record) bool { + fmt.Fprintf(&b, "\t\t- [%d] v%d (status = %s)\n", + index, + r.rls.Version, + r.rls.Info.Status.Code, + ) - return true - }) - } + return true + }) + } - _, err := w.Write(b.Bytes()) - return err + _, err := w.Write(b.Bytes()) + return err } // wlock locks mem for writing func (mem *Memory) wlock() func() { - mem.Lock() - return func() { mem.Unlock() } + mem.Lock() + return func() { mem.Unlock() } } // rlock locks mem for reading func (mem *Memory) rlock() func() { - mem.RLock() - return func() { mem.RUnlock() } + mem.RLock() + return func() { mem.RUnlock() } } // unlock calls fn which reverses a mem.rlock or mem.wlock. e.g: diff --git a/pkg/storage/driver/memory_test.go b/pkg/storage/driver/memory_test.go index 534d8a7de..8407e588c 100644 --- a/pkg/storage/driver/memory_test.go +++ b/pkg/storage/driver/memory_test.go @@ -17,152 +17,152 @@ limitations under the License. package driver import ( - "reflect" - "testing" + "reflect" + "testing" - rspb "k8s.io/helm/pkg/proto/hapi/release" + rspb "k8s.io/helm/pkg/proto/hapi/release" ) func TestMemoryName(t *testing.T) { - if mem := NewMemory(); mem.Name() != MemoryDriverName { - t.Errorf("Expected name to be %q, got %q", MemoryDriverName, mem.Name()) - } + if mem := NewMemory(); mem.Name() != MemoryDriverName { + t.Errorf("Expected name to be %q, got %q", MemoryDriverName, mem.Name()) + } } func TestMemoryCreate(t *testing.T) { - var tests = []struct { - desc string - rls *rspb.Release - err bool - }{ - { - "create should success", - releaseStub("rls-c", 1, rspb.Status_DEPLOYED), - false, - }, - { - "create should fail (release already exists)", - releaseStub("rls-a", 1, rspb.Status_DEPLOYED), - true, - }, - } - - ts := tsFixtureMemory(t) - for _, tt := range tests { - key := testKey(tt.rls.Name, tt.rls.Version) - rls := tt.rls - - if err := ts.Create(key, rls); err != nil { - if !tt.err { - t.Fatalf("failed to create %q: %s", tt.desc, err) - } - } - } + var tests = []struct { + desc string + rls *rspb.Release + err bool + }{ + { + "create should success", + releaseStub("rls-c", 1, rspb.Status_DEPLOYED), + false, + }, + { + "create should fail (release already exists)", + releaseStub("rls-a", 1, rspb.Status_DEPLOYED), + true, + }, + } + + ts := tsFixtureMemory(t) + for _, tt := range tests { + key := testKey(tt.rls.Name, tt.rls.Version) + rls := tt.rls + + if err := ts.Create(key, rls); err != nil { + if !tt.err { + t.Fatalf("failed to create %q: %s", tt.desc, err) + } + } + } } func TestMemoryGet(t *testing.T) { - var tests = []struct { - desc string - key string - err bool - }{ - {"release key should exist", "rls-a.v1", false}, - {"release key should not exist", "rls-a.v5", true}, - } - - ts := tsFixtureMemory(t) - for _, tt := range tests { - 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) - } - } - } + var tests = []struct { + desc string + key string + err bool + }{ + {"release key should exist", "rls-a.v1", false}, + {"release key should not exist", "rls-a.v5", true}, + } + + ts := tsFixtureMemory(t) + for _, tt := range tests { + 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) + } + } + } } func TestMemoryQuery(t *testing.T) { - var tests = []struct { - desc string - xlen int - lbs map[string]string - }{ - { - "should be 2 query results", - 2, - map[string]string{"STATUS": "DEPLOYED"}, - }, - } - - ts := tsFixtureMemory(t) - for _, tt := range tests { - l, err := ts.Query(tt.lbs) - if err != nil { - t.Fatalf("Failed to query: %s\n", err) - } - - if tt.xlen != len(l) { - t.Fatalf("Expected %d results, actual %d\n", tt.xlen, len(l)) - } - } + var tests = []struct { + desc string + xlen int + lbs map[string]string + }{ + { + "should be 2 query results", + 2, + map[string]string{"STATUS": "DEPLOYED"}, + }, + } + + ts := tsFixtureMemory(t) + for _, tt := range tests { + l, err := ts.Query(tt.lbs) + if err != nil { + t.Fatalf("Failed to query: %s\n", err) + } + + if tt.xlen != len(l) { + t.Fatalf("Expected %d results, actual %d\n", tt.xlen, len(l)) + } + } } func TestMemoryUpdate(t *testing.T) { - var tests = []struct { - desc string - key string - rls *rspb.Release - err bool - }{ - { - "update release status", - "rls-a.v4", - releaseStub("rls-a", 4, rspb.Status_SUPERSEDED), - false, - }, - { - "update release does not exist", - "rls-z.v1", - releaseStub("rls-z", 1, rspb.Status_DELETED), - true, - }, - } - - ts := tsFixtureMemory(t) - for _, tt := range tests { - if err := ts.Update(tt.key, tt.rls); err != nil { - if !tt.err { - t.Fatalf("Failed %q: %s\n", tt.desc, err) - } - continue - } - - r, err := ts.Get(tt.key) - if err != nil { - t.Fatalf("Failed to get: %s\n", err) - } - - if !reflect.DeepEqual(r, tt.rls) { - t.Fatalf("Expected %s, actual %s\n", tt.rls, r) - } - } + var tests = []struct { + desc string + key string + rls *rspb.Release + err bool + }{ + { + "update release status", + "rls-a.v4", + releaseStub("rls-a", 4, rspb.Status_SUPERSEDED), + false, + }, + { + "update release does not exist", + "rls-z.v1", + releaseStub("rls-z", 1, rspb.Status_DELETED), + true, + }, + } + + ts := tsFixtureMemory(t) + for _, tt := range tests { + if err := ts.Update(tt.key, tt.rls); err != nil { + if !tt.err { + t.Fatalf("Failed %q: %s\n", tt.desc, err) + } + continue + } + + r, err := ts.Get(tt.key) + if err != nil { + t.Fatalf("Failed to get: %s\n", err) + } + + if !reflect.DeepEqual(r, tt.rls) { + t.Fatalf("Expected %s, actual %s\n", tt.rls, r) + } + } } func TestMemoryDelete(t *testing.T) { - var tests = []struct { - desc string - key string - err bool - }{ - {"release key should exist", "rls-a.v1", false}, - {"release key should not exist", "rls-a.v5", true}, - } - - ts := tsFixtureMemory(t) - for _, tt := range tests { - if _, err := ts.Delete(tt.key); err != nil { - if !tt.err { - t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) - } - } - } + var tests = []struct { + desc string + key string + err bool + }{ + {"release key should exist", "rls-a.v1", false}, + {"release key should not exist", "rls-a.v5", true}, + } + + ts := tsFixtureMemory(t) + for _, tt := range tests { + if _, err := ts.Delete(tt.key); err != nil { + if !tt.err { + t.Fatalf("Failed %q to get '%s': %q\n", tt.desc, tt.key, err) + } + } + } } diff --git a/pkg/storage/driver/records.go b/pkg/storage/driver/records.go index 6b9ad5211..c8766d87f 100644 --- a/pkg/storage/driver/records.go +++ b/pkg/storage/driver/records.go @@ -1,10 +1,26 @@ -package driver +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 + + http://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 driver // import "k8s.io/helm/pkg/storage/driver" import ( - "sort" - "strconv" + "sort" + "strconv" - rspb "k8s.io/helm/pkg/proto/hapi/release" + rspb "k8s.io/helm/pkg/proto/hapi/release" ) // records holds a list of in-memory release records @@ -15,102 +31,102 @@ func (rs records) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] } func (rs records) Less(i, j int) bool { return rs[i].rls.Version < rs[j].rls.Version } func (rs *records) Add(r *record) error { - if r == nil { - return nil - } + if r == nil { + return nil + } - if rs.Exists(r.key) { - return ErrReleaseExists - } + if rs.Exists(r.key) { + return ErrReleaseExists + } - *rs = append(*rs, r) - sort.Sort(*rs) + *rs = append(*rs, r) + sort.Sort(*rs) - return nil + return nil } func (rs records) Get(key string) *record { - if i, ok := rs.Index(key); ok { - return rs[i] - } - return nil + if i, ok := rs.Index(key); ok { + return rs[i] + } + return nil } func (rs *records) Iter(fn func(int, *record) bool) { - cp := make([]*record, len(*rs)) - copy(cp, *rs) - - for i, r := range cp { - if !fn(i, r) { - return - } - } + cp := make([]*record, len(*rs)) + copy(cp, *rs) + + for i, r := range cp { + if !fn(i, r) { + return + } + } } func (rs *records) Index(key string) (int, bool) { - for i, r := range *rs { - if r.key == key { - return i, true - } - } - return -1, false + for i, r := range *rs { + if r.key == key { + return i, true + } + } + return -1, false } func (rs records) Exists(key string) bool { - _, ok := rs.Index(key) - return ok + _, ok := rs.Index(key) + return ok } func (rs *records) Remove(key string) (r *record) { - if i, ok := rs.Index(key); ok { - return rs.removeAt(i) - } - return nil + if i, ok := rs.Index(key); ok { + return rs.removeAt(i) + } + return nil } func (rs *records) Replace(key string, rec *record) *record { - if i, ok := rs.Index(key); ok { - old := (*rs)[i] - (*rs)[i] = rec - return old - } - return nil + if i, ok := rs.Index(key); ok { + old := (*rs)[i] + (*rs)[i] = rec + return old + } + return nil } func (rs records) FindByVersion(vers int32) (int, bool) { - i := sort.Search(len(rs), func(i int) bool { - return rs[i].rls.Version == vers - }) - if i < len(rs) && rs[i].rls.Version == vers { - return i, true - } - return i, false + i := sort.Search(len(rs), func(i int) bool { + return rs[i].rls.Version == vers + }) + if i < len(rs) && rs[i].rls.Version == vers { + return i, true + } + return i, false } func (rs *records) removeAt(index int) *record { - r := (*rs)[index] - (*rs)[index] = nil - copy((*rs)[index:], (*rs)[index+1:]) - *rs = (*rs)[:len(*rs)-1] - return r + r := (*rs)[index] + (*rs)[index] = nil + copy((*rs)[index:], (*rs)[index+1:]) + *rs = (*rs)[:len(*rs)-1] + return r } // record is the data structure used to cache releases // for the in-memory storage driver type record struct { - key string - lbs labels - rls *rspb.Release + key string + lbs labels + rls *rspb.Release } // newRecord creates a new in-memory release record func newRecord(key string, rls *rspb.Release) *record { - var lbs labels + var lbs labels - lbs.init() - lbs.set("NAME", rls.Name) - lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)]) - lbs.set("VERSION", strconv.Itoa(int(rls.Version))) + lbs.init() + lbs.set("NAME", rls.Name) + lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)]) + lbs.set("VERSION", strconv.Itoa(int(rls.Version))) - return &record{key: key, lbs: lbs, rls: rls} + return &record{key: key, lbs: lbs, rls: rls} } diff --git a/pkg/storage/driver/records_test.go b/pkg/storage/driver/records_test.go index 3095dd210..3597072f8 100644 --- a/pkg/storage/driver/records_test.go +++ b/pkg/storage/driver/records_test.go @@ -1,71 +1,87 @@ -package driver +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 + + http://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 driver // import "k8s.io/helm/pkg/storage/driver" import ( - "testing" + "testing" - rspb "k8s.io/helm/pkg/proto/hapi/release" + rspb "k8s.io/helm/pkg/proto/hapi/release" ) func TestRecordsAdd(t *testing.T) { - rs := records([]*record{ - newRecord("rls-a.v1", releaseStub("rls-a", 1, rspb.Status_SUPERSEDED)), - newRecord("rls-a.v2", releaseStub("rls-a", 2, rspb.Status_DEPLOYED)), - }) + rs := records([]*record{ + newRecord("rls-a.v1", releaseStub("rls-a", 1, rspb.Status_SUPERSEDED)), + newRecord("rls-a.v2", releaseStub("rls-a", 2, rspb.Status_DEPLOYED)), + }) - var tests = []struct { - desc string - key string - ok bool - rec *record - }{ - { - "add valid key", - "rls-a.v3", - false, - newRecord("rls-a.v3", releaseStub("rls-a", 3, rspb.Status_SUPERSEDED)), - }, - { - "add already existing key", - "rls-a.v1", - true, - newRecord("rls-a.v1", releaseStub("rls-a", 1, rspb.Status_DEPLOYED)), - }, - } + var tests = []struct { + desc string + key string + ok bool + rec *record + }{ + { + "add valid key", + "rls-a.v3", + false, + newRecord("rls-a.v3", releaseStub("rls-a", 3, rspb.Status_SUPERSEDED)), + }, + { + "add already existing key", + "rls-a.v1", + true, + newRecord("rls-a.v1", releaseStub("rls-a", 1, rspb.Status_DEPLOYED)), + }, + } - for _, tt := range tests { - if err := rs.Add(tt.rec); err != nil { - if !tt.ok { - t.Fatalf("failed: %q: %s\n", tt.desc, err) - } - } - } + for _, tt := range tests { + if err := rs.Add(tt.rec); err != nil { + if !tt.ok { + t.Fatalf("failed: %q: %s\n", tt.desc, err) + } + } + } } func TestRecordsRemove(t *testing.T) { - var tests = []struct { - desc string - key string - ok bool - }{ - {"remove valid key", "rls-a.v1", false}, - {"remove invalid key", "rls-a.v", true}, - {"remove non-existant key", "rls-z.v1", true}, - } + var tests = []struct { + desc string + key string + ok bool + }{ + {"remove valid key", "rls-a.v1", false}, + {"remove invalid key", "rls-a.v", true}, + {"remove non-existant key", "rls-z.v1", true}, + } - rs := records([]*record{ - newRecord("rls-a.v1", releaseStub("rls-a", 1, rspb.Status_SUPERSEDED)), - newRecord("rls-a.v2", releaseStub("rls-a", 2, rspb.Status_DEPLOYED)), - }) + rs := records([]*record{ + newRecord("rls-a.v1", releaseStub("rls-a", 1, rspb.Status_SUPERSEDED)), + newRecord("rls-a.v2", releaseStub("rls-a", 2, rspb.Status_DEPLOYED)), + }) - for _, tt := range tests { - if r := rs.Remove(tt.key); r == nil { - if !tt.ok { - t.Fatalf("Failed to %q (key = %s). Expected nil, got %s", - tt.desc, - tt.key, - r, - ) - } - } - } + for _, tt := range tests { + if r := rs.Remove(tt.key); r == nil { + if !tt.ok { + t.Fatalf("Failed to %q (key = %s). Expected nil, got %s", + tt.desc, + tt.key, + r, + ) + } + } + } } diff --git a/pkg/storage/driver/testing.go b/pkg/storage/driver/testing.go index 425d270bc..31fd3fd6b 100644 --- a/pkg/storage/driver/testing.go +++ b/pkg/storage/driver/testing.go @@ -1,119 +1,135 @@ -package driver +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 + + http://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 driver // import "k8s.io/helm/pkg/storage/driver" import ( - "fmt" - "testing" + "fmt" + "testing" - rspb "k8s.io/helm/pkg/proto/hapi/release" - "k8s.io/kubernetes/pkg/client/unversioned" - kberrs "k8s.io/kubernetes/pkg/api/errors" - "k8s.io/kubernetes/pkg/api" + rspb "k8s.io/helm/pkg/proto/hapi/release" + "k8s.io/kubernetes/pkg/api" + kberrs "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/client/unversioned" ) func releaseStub(name string, vers int32, code rspb.Status_Code) *rspb.Release { - return &rspb.Release{ - Name: name, - Version: vers, - Info: &rspb.Info{Status: &rspb.Status{Code: code}}, - } + return &rspb.Release{ + Name: name, + Version: vers, + Info: &rspb.Info{Status: &rspb.Status{Code: code}}, + } } func testKey(name string, vers int32) string { - return fmt.Sprintf("%s.v%d", name, vers) + return fmt.Sprintf("%s.v%d", name, vers) } func tsFixtureMemory(t *testing.T) *Memory { - hs := []*rspb.Release{ - // rls-a - releaseStub("rls-a", 4, rspb.Status_DEPLOYED), - releaseStub("rls-a", 1, rspb.Status_SUPERSEDED), - releaseStub("rls-a", 3, rspb.Status_SUPERSEDED), - releaseStub("rls-a", 2, rspb.Status_SUPERSEDED), - // rls-b - releaseStub("rls-b", 4, rspb.Status_DEPLOYED), - releaseStub("rls-b", 1, rspb.Status_SUPERSEDED), - releaseStub("rls-b", 3, rspb.Status_SUPERSEDED), - releaseStub("rls-b", 2, rspb.Status_SUPERSEDED), - } - - mem := NewMemory() - 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) - } - } - return mem + hs := []*rspb.Release{ + // rls-a + releaseStub("rls-a", 4, rspb.Status_DEPLOYED), + releaseStub("rls-a", 1, rspb.Status_SUPERSEDED), + releaseStub("rls-a", 3, rspb.Status_SUPERSEDED), + releaseStub("rls-a", 2, rspb.Status_SUPERSEDED), + // rls-b + releaseStub("rls-b", 4, rspb.Status_DEPLOYED), + releaseStub("rls-b", 1, rspb.Status_SUPERSEDED), + releaseStub("rls-b", 3, rspb.Status_SUPERSEDED), + releaseStub("rls-b", 2, rspb.Status_SUPERSEDED), + } + + mem := NewMemory() + 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) + } + } + return mem } // newTestFixture initializes a MockConfigMapsInterface. // ConfigMaps are created for each release provided. func newTestFixtureCfgMaps(t *testing.T, releases ...*rspb.Release) *ConfigMaps { - var mock MockConfigMapsInterface - mock.Init(t, releases...) + var mock MockConfigMapsInterface + mock.Init(t, releases...) - return NewConfigMaps(&mock) + return NewConfigMaps(&mock) } // MockConfigMapsInterface mocks a kubernetes ConfigMapsInterface type MockConfigMapsInterface struct { - unversioned.ConfigMapsInterface + unversioned.ConfigMapsInterface - objects map[string]*api.ConfigMap + objects map[string]*api.ConfigMap } func (mock *MockConfigMapsInterface) Init(t *testing.T, releases ...*rspb.Release) { - mock.objects = map[string]*api.ConfigMap{} + mock.objects = map[string]*api.ConfigMap{} - for _, rls := range releases { - objkey := testKey(rls.Name, rls.Version) + for _, rls := range releases { + objkey := testKey(rls.Name, rls.Version) - cfgmap, err := newConfigMapsObject(objkey, rls, nil) - if err != nil { - t.Fatalf("Failed to create configmap: %s", err) - } - mock.objects[objkey] = cfgmap - } + cfgmap, err := newConfigMapsObject(objkey, rls, nil) + if err != nil { + t.Fatalf("Failed to create configmap: %s", err) + } + mock.objects[objkey] = cfgmap + } } func (mock *MockConfigMapsInterface) Get(name string) (*api.ConfigMap, error) { - object, ok := mock.objects[name] - if !ok { - return nil, kberrs.NewNotFound(api.Resource("tests"), name) - } - return object, nil + object, ok := mock.objects[name] + if !ok { + return nil, kberrs.NewNotFound(api.Resource("tests"), name) + } + return object, nil } func (mock *MockConfigMapsInterface) List(opts api.ListOptions) (*api.ConfigMapList, error) { - var list api.ConfigMapList - for _, cfgmap := range mock.objects { - list.Items = append(list.Items, *cfgmap) - } - return &list, nil + var list api.ConfigMapList + for _, cfgmap := range mock.objects { + list.Items = append(list.Items, *cfgmap) + } + return &list, nil } func (mock *MockConfigMapsInterface) Create(cfgmap *api.ConfigMap) (*api.ConfigMap, error) { - name := cfgmap.ObjectMeta.Name - if object, ok := mock.objects[name]; ok { - return object, kberrs.NewAlreadyExists(api.Resource("tests"), name) - } - mock.objects[name] = cfgmap - return cfgmap, nil + name := cfgmap.ObjectMeta.Name + if object, ok := mock.objects[name]; ok { + return object, kberrs.NewAlreadyExists(api.Resource("tests"), name) + } + mock.objects[name] = cfgmap + return cfgmap, nil } func (mock *MockConfigMapsInterface) Update(cfgmap *api.ConfigMap) (*api.ConfigMap, error) { - name := cfgmap.ObjectMeta.Name - if _, ok := mock.objects[name]; !ok { - return nil, kberrs.NewNotFound(api.Resource("tests"), name) - } - mock.objects[name] = cfgmap - return cfgmap, nil + name := cfgmap.ObjectMeta.Name + if _, ok := mock.objects[name]; !ok { + return nil, kberrs.NewNotFound(api.Resource("tests"), name) + } + mock.objects[name] = cfgmap + return cfgmap, nil } func (mock *MockConfigMapsInterface) Delete(name string) error { - if _, ok := mock.objects[name]; !ok { - return kberrs.NewNotFound(api.Resource("tests"), name) - } - delete(mock.objects, name) - return nil + if _, ok := mock.objects[name]; !ok { + return kberrs.NewNotFound(api.Resource("tests"), name) + } + delete(mock.objects, name) + return nil } diff --git a/pkg/storage/filter.go b/pkg/storage/filter.go index 91846b006..c23f8c94d 100644 --- a/pkg/storage/filter.go +++ b/pkg/storage/filter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package storage +package storage // import "k8s.io/helm/pkg/storage" import rspb "k8s.io/helm/pkg/proto/hapi/release" diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 534425ad5..1301cc9f3 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -17,127 +17,127 @@ limitations under the License. package storage // import "k8s.io/helm/pkg/storage" import ( - "fmt" - "log" + "fmt" + "log" - rspb "k8s.io/helm/pkg/proto/hapi/release" - "k8s.io/helm/pkg/storage/driver" + rspb "k8s.io/helm/pkg/proto/hapi/release" + "k8s.io/helm/pkg/storage/driver" ) // Storage represents a storage engine for a Release. type Storage struct { - driver.Driver + driver.Driver } // Get retrieves the release from storage. An error is returned // if the storage driver failed to fetch the release, or the // release identified by the key, version pair does not exist. func (s *Storage) Get(name string, version int32) (*rspb.Release, error) { - log.Printf("Getting release %q (v%d) from storage\n", name, version) - return s.Driver.Get(makeKey(name, version)) + log.Printf("Getting release %q (v%d) from storage\n", name, version) + return s.Driver.Get(makeKey(name, version)) } // Create creates a new storage entry holding the release. An // error is returned if the storage driver failed to store the // release, or a release with identical an key already exists. func (s *Storage) Create(rls *rspb.Release) error { - log.Printf("Create release %q (v%d) in storage\n", rls.Name, rls.Version) - return s.Driver.Create(makeKey(rls.Name, rls.Version), rls) + log.Printf("Create release %q (v%d) in storage\n", rls.Name, rls.Version) + return s.Driver.Create(makeKey(rls.Name, rls.Version), rls) } // Update update the release in storage. An error is returned if the // storage backend fails to update the release or if the release // does not exist. func (s *Storage) Update(rls *rspb.Release) error { - log.Printf("Updating %q (v%d) in storage\n", rls.Name, rls.Version) - return s.Driver.Update(makeKey(rls.Name, rls.Version), rls) + log.Printf("Updating %q (v%d) in storage\n", rls.Name, rls.Version) + return s.Driver.Update(makeKey(rls.Name, rls.Version), rls) } // Delete deletes the release from storage. An error is returned if // the storage backend fails to delete the release or if the release // does not exist. func (s *Storage) Delete(name string, version int32) (*rspb.Release, error) { - log.Printf("Deleting release %q (v%d) from storage\n", name, version) - return s.Driver.Delete(makeKey(name, version)) + log.Printf("Deleting release %q (v%d) from storage\n", name, version) + return s.Driver.Delete(makeKey(name, version)) } // ListReleases returns all releases from storage. An error is returned if the // storage backend fails to retrieve the releases. func (s *Storage) ListReleases() ([]*rspb.Release, error) { - log.Println("Listing all releases in storage") - return s.Driver.List(func(_ *rspb.Release) bool { return true }) + log.Println("Listing all releases in storage") + return s.Driver.List(func(_ *rspb.Release) bool { return true }) } // ListDeleted returns all releases with Status == DELETED. An error is returned // if the storage backend fails to retrieve the releases. func (s *Storage) ListDeleted() ([]*rspb.Release, error) { - log.Println("List deleted releases in storage") - return s.Driver.List(func(rls *rspb.Release) bool { - return StatusFilter(rspb.Status_DELETED).Check(rls) - }) + log.Println("List deleted releases in storage") + return s.Driver.List(func(rls *rspb.Release) bool { + return StatusFilter(rspb.Status_DELETED).Check(rls) + }) } // ListDeployed returns all releases with Status == DEPLOYED. An error is returned // if the storage backend fails to retrieve the releases. func (s *Storage) ListDeployed() ([]*rspb.Release, error) { - log.Println("Listing all deployed releases in storage") - return s.Driver.List(func(rls *rspb.Release) bool { - return StatusFilter(rspb.Status_DEPLOYED).Check(rls) - }) + log.Println("Listing all deployed releases in storage") + return s.Driver.List(func(rls *rspb.Release) bool { + return StatusFilter(rspb.Status_DEPLOYED).Check(rls) + }) } // ListFilterAll returns the set of releases satisfying satisfying the predicate // (filter0 && filter1 && ... && filterN), i.e. a Release is included in the results // if and only if all filters return true. func (s *Storage) ListFilterAll(filters ...FilterFunc) ([]*rspb.Release, error) { - log.Println("Listing all releases with filter") - return s.Driver.List(func(rls *rspb.Release) bool { - return All(filters...).Check(rls) - }) + log.Println("Listing all releases with filter") + return s.Driver.List(func(rls *rspb.Release) bool { + return All(filters...).Check(rls) + }) } // ListFilterAny returns the set of releases satisfying satisfying the predicate // (filter0 || filter1 || ... || filterN), i.e. a Release is included in the results // if at least one of the filters returns true. func (s *Storage) ListFilterAny(filters ...FilterFunc) ([]*rspb.Release, error) { - log.Println("Listing any releases with filter") - return s.Driver.List(func(rls *rspb.Release) bool { - return Any(filters...).Check(rls) - }) + log.Println("Listing any releases with filter") + return s.Driver.List(func(rls *rspb.Release) bool { + return Any(filters...).Check(rls) + }) } // Deployed returns the deployed release with the provided release name, or // returns ErrReleaseNotFound if not found. func (s *Storage) Deployed(name string) (*rspb.Release, error) { - log.Printf("Getting deployed release from '%s' history\n", name) - - ls, err := s.Driver.Query(map[string]string{ - "NAME": name, - "STATUS": "DEPLOYED", - }) - switch { - case err != nil: - return nil, err - case len(ls) == 0: - return nil, fmt.Errorf("'%s' has no deployed releases", name) - default: - return ls[0], nil - } + log.Printf("Getting deployed release from '%s' history\n", name) + + ls, err := s.Driver.Query(map[string]string{ + "NAME": name, + "STATUS": "DEPLOYED", + }) + switch { + case err != nil: + return nil, err + case len(ls) == 0: + return nil, fmt.Errorf("'%s' has no deployed releases", name) + default: + return ls[0], nil + } } // makeKey concatenates a release name and version into // a string with format ```<release_name>#v<version>```. // This key is used to uniquely identify storage objects. func makeKey(rlsname string, version int32) string { - return fmt.Sprintf("%s.v%d", rlsname, version) + return fmt.Sprintf("%s.v%d", rlsname, version) } // Init initializes a new storage backend with the driver d. // If d is nil, the default in-memory driver is used. func Init(d driver.Driver) *Storage { - // default driver is in memory - if d == nil { - d = driver.NewMemory() - } - return &Storage{Driver: d} + // default driver is in memory + if d == nil { + d = driver.NewMemory() + } + return &Storage{Driver: d} } diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 4aae0dd06..42151b418 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -17,195 +17,195 @@ limitations under the License. package storage // import "k8s.io/helm/pkg/storage" import ( - "fmt" - "reflect" - "testing" + "fmt" + "reflect" + "testing" - rspb "k8s.io/helm/pkg/proto/hapi/release" - "k8s.io/helm/pkg/storage/driver" + rspb "k8s.io/helm/pkg/proto/hapi/release" + "k8s.io/helm/pkg/storage/driver" ) func TestStorageCreate(t *testing.T) { - // initialize storage - storage := Init(driver.NewMemory()) + // initialize storage + storage := Init(driver.NewMemory()) - // create fake release - rls := ReleaseTestData{ - Name: "angry-beaver", - Version: 1, - }.ToRelease() + // create fake release + rls := ReleaseTestData{ + Name: "angry-beaver", + Version: 1, + }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") + assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") - // fetch the release - res, err := storage.Get(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "QueryRelease") + // fetch the release + res, err := storage.Get(rls.Name, rls.Version) + assertErrNil(t.Fatal, err, "QueryRelease") - // verify the fetched and created release are the same - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %q, got %q", rls, res) - } + // verify the fetched and created release are the same + if !reflect.DeepEqual(rls, res) { + t.Fatalf("Expected %q, got %q", rls, res) + } } func TestStorageUpdate(t *testing.T) { - // initialize storage - storage := Init(driver.NewMemory()) - - // create fake release - rls := ReleaseTestData{ - Name: "angry-beaver", - Version: 1, - Status: rspb.Status_DEPLOYED, - }.ToRelease() - - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") - - // modify the release - rls.Info.Status.Code = rspb.Status_DELETED - assertErrNil(t.Fatal, storage.Update(rls), "UpdateRelease") - - // retrieve the updated release - res, err := storage.Get(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "QueryRelease") - - // verify updated and fetched releases are the same. - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %q, got %q", rls, res) - } + // initialize storage + storage := Init(driver.NewMemory()) + + // create fake release + rls := ReleaseTestData{ + Name: "angry-beaver", + Version: 1, + Status: rspb.Status_DEPLOYED, + }.ToRelease() + + assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") + + // modify the release + rls.Info.Status.Code = rspb.Status_DELETED + assertErrNil(t.Fatal, storage.Update(rls), "UpdateRelease") + + // retrieve the updated release + res, err := storage.Get(rls.Name, rls.Version) + assertErrNil(t.Fatal, err, "QueryRelease") + + // verify updated and fetched releases are the same. + if !reflect.DeepEqual(rls, res) { + t.Fatalf("Expected %q, got %q", rls, res) + } } func TestStorageDelete(t *testing.T) { - // initialize storage - storage := Init(driver.NewMemory()) + // initialize storage + storage := Init(driver.NewMemory()) - // create fake release - rls := ReleaseTestData{ - Name: "angry-beaver", - Version: 1, - }.ToRelease() + // create fake release + rls := ReleaseTestData{ + Name: "angry-beaver", + Version: 1, + }.ToRelease() - assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") + assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease") - // delete the release - res, err := storage.Delete(rls.Name, rls.Version) - assertErrNil(t.Fatal, err, "DeleteRelease") + // delete the release + res, err := storage.Delete(rls.Name, rls.Version) + assertErrNil(t.Fatal, err, "DeleteRelease") - // verify updated and fetched releases are the same. - if !reflect.DeepEqual(rls, res) { - t.Fatalf("Expected %q, got %q", rls, res) - } + // verify updated and fetched releases are the same. + if !reflect.DeepEqual(rls, res) { + t.Fatalf("Expected %q, got %q", rls, res) + } } func TestStorageList(t *testing.T) { - // initialize storage - storage := Init(driver.NewMemory()) - - // setup storage with test releases - setup := func() { - // release records - rls0 := ReleaseTestData{Name: "happy-catdog", Status: rspb.Status_SUPERSEDED}.ToRelease() - rls1 := ReleaseTestData{Name: "livid-human", Status: rspb.Status_SUPERSEDED}.ToRelease() - rls2 := ReleaseTestData{Name: "relaxed-cat", Status: rspb.Status_SUPERSEDED}.ToRelease() - rls3 := ReleaseTestData{Name: "hungry-hippo", Status: rspb.Status_DEPLOYED}.ToRelease() - rls4 := ReleaseTestData{Name: "angry-beaver", Status: rspb.Status_DEPLOYED}.ToRelease() - rls5 := ReleaseTestData{Name: "opulent-frog", Status: rspb.Status_DELETED}.ToRelease() - rls6 := ReleaseTestData{Name: "happy-liger", Status: rspb.Status_DELETED}.ToRelease() - - // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'rls0'") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'rls1'") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'rls2'") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'rls3'") - assertErrNil(t.Fatal, storage.Create(rls4), "Storing release 'rls4'") - assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'rls5'") - assertErrNil(t.Fatal, storage.Create(rls6), "Storing release 'rls6'") - } - - var listTests = []struct { - Description string - NumExpected int - ListFunc func() ([]*rspb.Release, error) - }{ - {"ListDeleted", 2, storage.ListDeleted}, - {"ListDeployed", 2, storage.ListDeployed}, - {"ListReleases", 7, storage.ListReleases}, - } - - setup() - - for _, tt := range listTests { - list, err := tt.ListFunc() - assertErrNil(t.Fatal, err, tt.Description) - // verify the count of releases returned - if len(list) != tt.NumExpected { - t.Errorf("ListReleases(%s): expected %d, actual %d", - tt.Description, - tt.NumExpected, - len(list)) - } - } + // initialize storage + storage := Init(driver.NewMemory()) + + // setup storage with test releases + setup := func() { + // release records + rls0 := ReleaseTestData{Name: "happy-catdog", Status: rspb.Status_SUPERSEDED}.ToRelease() + rls1 := ReleaseTestData{Name: "livid-human", Status: rspb.Status_SUPERSEDED}.ToRelease() + rls2 := ReleaseTestData{Name: "relaxed-cat", Status: rspb.Status_SUPERSEDED}.ToRelease() + rls3 := ReleaseTestData{Name: "hungry-hippo", Status: rspb.Status_DEPLOYED}.ToRelease() + rls4 := ReleaseTestData{Name: "angry-beaver", Status: rspb.Status_DEPLOYED}.ToRelease() + rls5 := ReleaseTestData{Name: "opulent-frog", Status: rspb.Status_DELETED}.ToRelease() + rls6 := ReleaseTestData{Name: "happy-liger", Status: rspb.Status_DELETED}.ToRelease() + + // create the release records in the storage + assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'rls0'") + assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'rls1'") + assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'rls2'") + assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'rls3'") + assertErrNil(t.Fatal, storage.Create(rls4), "Storing release 'rls4'") + assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'rls5'") + assertErrNil(t.Fatal, storage.Create(rls6), "Storing release 'rls6'") + } + + var listTests = []struct { + Description string + NumExpected int + ListFunc func() ([]*rspb.Release, error) + }{ + {"ListDeleted", 2, storage.ListDeleted}, + {"ListDeployed", 2, storage.ListDeployed}, + {"ListReleases", 7, storage.ListReleases}, + } + + setup() + + for _, tt := range listTests { + list, err := tt.ListFunc() + assertErrNil(t.Fatal, err, tt.Description) + // verify the count of releases returned + if len(list) != tt.NumExpected { + t.Errorf("ListReleases(%s): expected %d, actual %d", + tt.Description, + tt.NumExpected, + len(list)) + } + } } func TestStorageDeployed(t *testing.T) { - storage := Init(driver.NewMemory()) - - const name = "angry-bird" - const vers = int32(4) - - // setup storage with test releases - setup := func() { - // release records - rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.Status_SUPERSEDED}.ToRelease() - rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.Status_SUPERSEDED}.ToRelease() - rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.Status_SUPERSEDED}.ToRelease() - rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.Status_DEPLOYED}.ToRelease() - - // create the release records in the storage - assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") - assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") - assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") - assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") - } - - setup() - - rls, err := storage.Deployed(name) - if err != nil { - t.Fatalf("Failed to query for deployed release: %s\n", err) - } - - switch { - case rls == nil: - t.Fatalf("Release is nil") - case rls.Name != name: - t.Fatalf("Expected release name %q, actual %q\n", name, rls.Name) - case rls.Version != vers: - t.Fatalf("Expected release version %d, actual %d\n", vers, rls.Version) - case rls.Info.Status.Code != rspb.Status_DEPLOYED: - t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rls.Info.Status.Code) - } + storage := Init(driver.NewMemory()) + + const name = "angry-bird" + const vers = int32(4) + + // setup storage with test releases + setup := func() { + // release records + rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.Status_SUPERSEDED}.ToRelease() + rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.Status_SUPERSEDED}.ToRelease() + rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.Status_SUPERSEDED}.ToRelease() + rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.Status_DEPLOYED}.ToRelease() + + // create the release records in the storage + assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)") + assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)") + assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)") + assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)") + } + + setup() + + rls, err := storage.Deployed(name) + if err != nil { + t.Fatalf("Failed to query for deployed release: %s\n", err) + } + + switch { + case rls == nil: + t.Fatalf("Release is nil") + case rls.Name != name: + t.Fatalf("Expected release name %q, actual %q\n", name, rls.Name) + case rls.Version != vers: + t.Fatalf("Expected release version %d, actual %d\n", vers, rls.Version) + case rls.Info.Status.Code != rspb.Status_DEPLOYED: + t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rls.Info.Status.Code) + } } type ReleaseTestData struct { - Name string - Version int32 - Manifest string - Namespace string - Status rspb.Status_Code + Name string + Version int32 + Manifest string + Namespace string + Status rspb.Status_Code } func (test ReleaseTestData) ToRelease() *rspb.Release { - return &rspb.Release{ - Name: test.Name, - Version: test.Version, - Manifest: test.Manifest, - Namespace: test.Namespace, - Info: &rspb.Info{Status: &rspb.Status{Code: test.Status}}, - } + return &rspb.Release{ + Name: test.Name, + Version: test.Version, + Manifest: test.Manifest, + Namespace: test.Namespace, + Info: &rspb.Info{Status: &rspb.Status{Code: test.Status}}, + } } func assertErrNil(eh func(args ...interface{}), err error, message string) { - if err != nil { - eh(fmt.Sprintf("%s: %q", message, err)) - } + if err != nil { + eh(fmt.Sprintf("%s: %q", message, err)) + } } -- GitLab