Commit 41be5f59 authored by fibonacci1729's avatar fibonacci1729

chore(helm): add test coverage to pkg/helm

parent 7a4e53ec
This diff is collapsed.
/*
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 helm // import "k8s.io/helm/pkg/helm"
import (
"errors"
"path/filepath"
"reflect"
"testing"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"k8s.io/helm/pkg/chartutil"
cpb "k8s.io/helm/pkg/proto/hapi/chart"
rls "k8s.io/helm/pkg/proto/hapi/release"
tpb "k8s.io/helm/pkg/proto/hapi/services"
)
// path to example charts relative to pkg/helm.
const chartsDir = "../../docs/examples/"
// sentinel error to indicate to the helm client to not send the request to tiller.
var errSkip = errors.New("test: skip")
// Verify ReleaseListOption's are applied to a ListReleasesRequest correctly.
func TestListReleases_VerifyOptions(t *testing.T) {
// Options testdata
var limit = 2
var offset = "offset"
var filter = "filter"
var sortBy = int32(2)
var sortOrd = int32(1)
var codes = []rls.Status_Code{
rls.Status_FAILED,
rls.Status_DELETED,
rls.Status_DEPLOYED,
rls.Status_SUPERSEDED,
}
// Expected ListReleasesRequest message
exp := &tpb.ListReleasesRequest{
Limit: int64(limit),
Offset: offset,
Filter: filter,
SortBy: tpb.ListSort_SortBy(sortBy),
SortOrder: tpb.ListSort_SortOrder(sortOrd),
StatusCodes: codes,
}
// Options used in ListReleases
ops := []ReleaseListOption{
ReleaseListSort(sortBy),
ReleaseListOrder(sortOrd),
ReleaseListLimit(limit),
ReleaseListOffset(offset),
ReleaseListFilter(filter),
ReleaseListStatuses(codes),
}
// BeforeCall option to intercept helm client ListReleasesRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
switch act := msg.(type) {
case *tpb.ListReleasesRequest:
t.Logf("ListReleasesRequest: %#+v\n", act)
assert(t, exp, act)
default:
t.Fatalf("expected message of type ListReleasesRequest, got %T\n", act)
}
return errSkip
})
NewClient(b4c).ListReleases(ops...)
}
// Verify InstallOption's are applied to an InstallReleaseRequest correctly.
func TestInstallRelease_VerifyOptions(t *testing.T) {
// Options testdata
var disableHooks = true
var releaseName = "test"
var namespace = "default"
var reuseName = true
var dryRun = true
var chartName = "alpine"
var overrides = []byte("key1=value1,key2=value2")
// Expected InstallReleaseRequest message
exp := &tpb.InstallReleaseRequest{
Chart: loadChart(t, chartName),
Values: &cpb.Config{Raw: string(overrides)},
DryRun: dryRun,
Name: releaseName,
DisableHooks: disableHooks,
Namespace: namespace,
ReuseName: reuseName,
}
// Options used in InstallRelease
ops := []InstallOption{
ValueOverrides(overrides),
InstallDryRun(dryRun),
ReleaseName(releaseName),
InstallReuseName(reuseName),
InstallDisableHooks(disableHooks),
}
// BeforeCall option to intercept helm client InstallReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
switch act := msg.(type) {
case *tpb.InstallReleaseRequest:
t.Logf("InstallReleaseRequest: %#+v\n", act)
assert(t, exp, act)
default:
t.Fatalf("expected message of type InstallReleaseRequest, got %T\n", act)
}
return errSkip
})
NewClient(b4c).InstallRelease(chartName, namespace, ops...)
}
// Verify DeleteOptions's are applied to an UninstallReleaseRequest correctly.
func TestDeleteRelease_VerifyOptions(t *testing.T) {
// Options testdata
var releaseName = "test"
var disableHooks = true
var purgeFlag = true
// Expected DeleteReleaseRequest message
exp := &tpb.UninstallReleaseRequest{
Name: releaseName,
Purge: purgeFlag,
DisableHooks: disableHooks,
}
// Options used in DeleteRelease
ops := []DeleteOption{
DeletePurge(purgeFlag),
DeleteDisableHooks(disableHooks),
}
// BeforeCall option to intercept helm client DeleteReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
switch act := msg.(type) {
case *tpb.UninstallReleaseRequest:
t.Logf("UninstallReleaseRequest: %#+v\n", act)
assert(t, exp, act)
default:
t.Fatalf("expected message of type UninstallReleaseRequest, got %T\n", act)
}
return errSkip
})
NewClient(b4c).DeleteRelease(releaseName, ops...)
}
// Verify UpdateOption's are applied to an UpdateReleaseRequest correctly.
func TestUpdateRelease_VerifyOptions(t *testing.T) {
// Options testdata
var chartName = "alpine"
var releaseName = "test"
var disableHooks = true
var overrides = []byte("key1=value1,key2=value2")
var dryRun = false
// Expected UpdateReleaseRequest message
exp := &tpb.UpdateReleaseRequest{
Name: releaseName,
Chart: loadChart(t, chartName),
Values: &cpb.Config{Raw: string(overrides)},
DryRun: dryRun,
DisableHooks: disableHooks,
}
// Options used in UpdateRelease
ops := []UpdateOption{
UpgradeDryRun(dryRun),
UpdateValueOverrides(overrides),
UpgradeDisableHooks(disableHooks),
}
// BeforeCall option to intercept helm client UpdateReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
switch act := msg.(type) {
case *tpb.UpdateReleaseRequest:
t.Logf("UpdateReleaseRequest: %#+v\n", act)
assert(t, exp, act)
default:
t.Fatalf("expected message of type UpdateReleaseRequest, got %T\n", act)
}
return errSkip
})
NewClient(b4c).UpdateRelease(releaseName, chartName, ops...)
}
// Verify RollbackOption's are applied to a RollbackReleaseRequest correctly.
func TestRollbackRelease_VerifyOptions(t *testing.T) {
// Options testdata
var disableHooks = true
var releaseName = "test"
var revision = int32(2)
var dryRun = true
// Expected RollbackReleaseRequest message
exp := &tpb.RollbackReleaseRequest{
Name: releaseName,
DryRun: dryRun,
Version: revision,
DisableHooks: disableHooks,
}
// Options used in RollbackRelease
ops := []RollbackOption{
RollbackDryRun(dryRun),
RollbackVersion(revision),
RollbackDisableHooks(disableHooks),
}
// BeforeCall option to intercept helm client RollbackReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
switch act := msg.(type) {
case *tpb.RollbackReleaseRequest:
t.Logf("RollbackReleaseRequest: %#+v\n", act)
assert(t, exp, act)
default:
t.Fatalf("expected message of type RollbackReleaseRequest, got %T\n", act)
}
return errSkip
})
NewClient(b4c).RollbackRelease(releaseName, ops...)
}
// Verify StatusOption's are applied to a GetReleaseStatusRequest correctly.
func TestReleaseStatus_VerifyOptions(t *testing.T) {
// Options testdata
var releaseName = "test"
var revision = int32(2)
// Expected GetReleaseStatusRequest message
exp := &tpb.GetReleaseStatusRequest{
Name: releaseName,
Version: revision,
}
// BeforeCall option to intercept helm client GetReleaseStatusRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
switch act := msg.(type) {
case *tpb.GetReleaseStatusRequest:
t.Logf("GetReleaseStatusRequest: %#+v\n", act)
assert(t, exp, act)
default:
t.Fatalf("expected message of type GetReleaseStatusRequest, got %T\n", act)
}
return errSkip
})
NewClient(b4c).ReleaseStatus(releaseName, StatusReleaseVersion(revision))
}
// Verify ContentOption's are applied to a GetReleaseContentRequest correctly.
func TestReleaseContent_VerifyOptions(t *testing.T) {
// Options testdata
var releaseName = "test"
var revision = int32(2)
// Expected GetReleaseContentRequest message
exp := &tpb.GetReleaseContentRequest{
Name: releaseName,
Version: revision,
}
// BeforeCall option to intercept helm client GetReleaseContentRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
switch act := msg.(type) {
case *tpb.GetReleaseContentRequest:
t.Logf("GetReleaseContentRequest: %#+v\n", act)
assert(t, exp, act)
default:
t.Fatalf("expected message of type GetReleaseContentRequest, got %T\n", act)
}
return errSkip
})
NewClient(b4c).ReleaseContent(releaseName, ContentReleaseVersion(revision))
}
func assert(t *testing.T, expect, actual interface{}) {
if !reflect.DeepEqual(expect, actual) {
t.Fatalf("expected %#+v, actual %#+v\n", expect, actual)
}
}
func loadChart(t *testing.T, name string) *cpb.Chart {
c, err := chartutil.Load(filepath.Join(chartsDir, name))
if err != nil {
t.Fatalf("failed to load test chart (%q): %s\n", name, err)
}
return c
}
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package helm package helm
import ( import (
"github.com/golang/protobuf/proto"
"golang.org/x/net/context" "golang.org/x/net/context"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
...@@ -41,6 +42,8 @@ type options struct { ...@@ -41,6 +42,8 @@ type options struct {
reuseName bool reuseName bool
// if set, skip running hooks // if set, skip running hooks
disableHooks bool disableHooks bool
// name of release
releaseName string
// release list options are applied directly to the list releases request // release list options are applied directly to the list releases request
listReq rls.ListReleasesRequest listReq rls.ListReleasesRequest
// release install options are applied directly to the install release request // release install options are applied directly to the install release request
...@@ -55,6 +58,8 @@ type options struct { ...@@ -55,6 +58,8 @@ type options struct {
contentReq rls.GetReleaseContentRequest contentReq rls.GetReleaseContentRequest
// release rollback options are applied directly to the rollback release request // release rollback options are applied directly to the rollback release request
rollbackReq rls.RollbackReleaseRequest rollbackReq rls.RollbackReleaseRequest
// before intercepts client calls before sending
before func(context.Context, proto.Message) error
} }
// Host specifies the host address of the Tiller release server, (default = ":44134"). // Host specifies the host address of the Tiller release server, (default = ":44134").
...@@ -64,6 +69,15 @@ func Host(host string) Option { ...@@ -64,6 +69,15 @@ func Host(host string) Option {
} }
} }
// BeforeCall returns an option that allows intercepting a helm client rpc
// before being sent OTA to tiller. The intercepting function should return
// an error to indicate that the call should not proceed or nil otherwise.
func BeforeCall(fn func(context.Context, proto.Message) error) Option {
return func(opts *options) {
opts.before = fn
}
}
// ReleaseListOption allows specifying various settings // ReleaseListOption allows specifying various settings
// configurable by the helm client user for overriding // configurable by the helm client user for overriding
// the defaults used when running the `helm list` command. // the defaults used when running the `helm list` command.
...@@ -258,111 +272,8 @@ type UpdateOption func(*options) ...@@ -258,111 +272,8 @@ type UpdateOption func(*options)
// running the `helm rollback` command. // running the `helm rollback` command.
type RollbackOption func(*options) type RollbackOption func(*options)
// RPC helpers defined on `options` type. Note: These actually execute the
// the corresponding tiller RPC. There is no particular reason why these
// are APIs are hung off `options`, they are internal to pkg/helm to remain
// malleable.
// Executes tiller.ListReleases RPC.
func (o *options) rpcListReleases(rlc rls.ReleaseServiceClient, opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) {
// apply release list options
for _, opt := range opts {
opt(o)
}
s, err := rlc.ListReleases(NewContext(), &o.listReq)
if err != nil {
return nil, err
}
return s.Recv()
}
// NewContext creates a versioned context. // NewContext creates a versioned context.
func NewContext() context.Context { func NewContext() context.Context {
md := metadata.Pairs("x-helm-api-client", version.Version) md := metadata.Pairs("x-helm-api-client", version.Version)
return metadata.NewContext(context.TODO(), md) return metadata.NewContext(context.TODO(), md)
} }
// Executes tiller.InstallRelease RPC.
func (o *options) rpcInstallRelease(chr *cpb.Chart, rlc rls.ReleaseServiceClient, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
// apply the install options
for _, opt := range opts {
opt(o)
}
o.instReq.Chart = chr
o.instReq.Namespace = ns
o.instReq.DryRun = o.dryRun
o.instReq.DisableHooks = o.disableHooks
o.instReq.ReuseName = o.reuseName
return rlc.InstallRelease(NewContext(), &o.instReq)
}
// Executes tiller.UninstallRelease RPC.
func (o *options) rpcDeleteRelease(rlsName string, rlc rls.ReleaseServiceClient, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
for _, opt := range opts {
opt(o)
}
if o.dryRun {
// In the dry run case, just see if the release exists
r, err := o.rpcGetReleaseContent(rlsName, rlc)
if err != nil {
return &rls.UninstallReleaseResponse{}, err
}
return &rls.UninstallReleaseResponse{Release: r.Release}, nil
}
o.uninstallReq.Name = rlsName
o.uninstallReq.DisableHooks = o.disableHooks
return rlc.UninstallRelease(NewContext(), &o.uninstallReq)
}
// Executes tiller.UpdateRelease RPC.
func (o *options) rpcUpdateRelease(rlsName string, chr *cpb.Chart, rlc rls.ReleaseServiceClient, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
for _, opt := range opts {
opt(o)
}
o.updateReq.Chart = chr
o.updateReq.DryRun = o.dryRun
o.updateReq.Name = rlsName
return rlc.UpdateRelease(NewContext(), &o.updateReq)
}
// Executes tiller.UpdateRelease RPC.
func (o *options) rpcRollbackRelease(rlsName string, rlc rls.ReleaseServiceClient, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
for _, opt := range opts {
opt(o)
}
o.rollbackReq.DryRun = o.dryRun
o.rollbackReq.Name = rlsName
return rlc.RollbackRelease(NewContext(), &o.rollbackReq)
}
// Executes tiller.GetReleaseStatus RPC.
func (o *options) rpcGetReleaseStatus(rlsName string, rlc rls.ReleaseServiceClient, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
for _, opt := range opts {
opt(o)
}
o.statusReq.Name = rlsName
return rlc.GetReleaseStatus(NewContext(), &o.statusReq)
}
// Executes tiller.GetReleaseContent.
func (o *options) rpcGetReleaseContent(rlsName string, rlc rls.ReleaseServiceClient, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) {
for _, opt := range opts {
opt(o)
}
o.contentReq.Name = rlsName
return rlc.GetReleaseContent(NewContext(), &o.contentReq)
}
// Executes tiller.GetVersion RPC.
func (o *options) rpcGetVersion(rlc rls.ReleaseServiceClient, opts ...VersionOption) (*rls.GetVersionResponse, error) {
req := &rls.GetVersionRequest{}
return rlc.GetVersion(NewContext(), req)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment