Skip to content

Commit

Permalink
[kubeops] Implement framework for testing /kubeops/internal/handler (#…
Browse files Browse the repository at this point in the history
…1408)

* Implement framework for testing /kubeops/handler

Signed-off-by: Latiif <abdullatif.alshriaf@combitech.se>

* Use custom comparer for releases

Signed-off-by: Latiif <abdullatif.alshriaf@combitech.se>
  • Loading branch information
latiif authored and absoludity committed Jan 7, 2020
1 parent 6044a5d commit e946043
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 4 deletions.
142 changes: 142 additions & 0 deletions cmd/kubeops/internal/handler/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package handler

import (
"context"
"fmt"
"io/ioutil"
"net/http/httptest"
"strings"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/kubeapps/kubeapps/pkg/agent"
"github.com/kubeapps/kubeapps/pkg/auth"
authFake "github.com/kubeapps/kubeapps/pkg/auth/fake"
chartFake "github.com/kubeapps/kubeapps/pkg/chart/fake"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil"
kubefake "helm.sh/helm/v3/pkg/kube/fake"
"helm.sh/helm/v3/pkg/storage"
"helm.sh/helm/v3/pkg/storage/driver"

"helm.sh/helm/v3/pkg/release"
)

const defaultListLimit = 256

// newConfigFixture returns an agent.Config with fake clients
// and memory storage.
func newConfigFixture(t *testing.T) *agent.Config {
t.Helper()

return &agent.Config{
ActionConfig: &action.Configuration{
Releases: storage.Init(driver.NewMemory()),
KubeClient: &kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: ioutil.Discard}},
Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {
t.Helper()
t.Logf(format, v...)
},
},
ChartClient: &chartFake.FakeChart{},
AgentOptions: agent.Options{
ListLimit: defaultListLimit,
},
}
}

func TestActions(t *testing.T) {
type testScenario struct {
// Scenario params
Description string
ExistingReleases []release.Release
DisableAuth bool
// Request params
RequestBody string
RequestQuery string
Action string
Params map[string]string
// Expected result
StatusCode int
RemainingReleases []release.Release
ResponseBody string //optional
}

tests := []testScenario{}

for _, test := range tests {
t.Run(test.Description, func(t *testing.T) {
// Initialize environment for test
req := httptest.NewRequest("GET", fmt.Sprintf("http://foo.bar%s", test.RequestQuery), strings.NewReader(test.RequestBody))
if !test.DisableAuth {
fauth := &authFake.FakeAuth{}
ctx := context.WithValue(req.Context(), auth.UserKey, fauth)
req = req.WithContext(ctx)
}
response := httptest.NewRecorder()
cfg := newConfigFixture(t)
for i := range test.ExistingReleases {
err := cfg.ActionConfig.Releases.Create(&test.ExistingReleases[i])
if err != nil {
t.Errorf("Failed to initiate test: %v", err)
}
}
// Perform request
switch test.Action {
default:
t.Errorf("Unexpected action %s", test.Action)
}
// Check result
if response.Code != test.StatusCode {
t.Errorf("Expecting a StatusCode %d, received %d", test.StatusCode, response.Code)
}
releases := derefReleases(cfg.ActionConfig.Releases)
rlsComparer := cmp.Comparer(func(x release.Release, y release.Release) bool {
return x.Name == y.Name &&
x.Version == y.Version &&
x.Namespace == y.Namespace &&
x.Info.Status == y.Info.Status &&
x.Chart.Name() == y.Chart.Name() &&
x.Manifest == y.Manifest &&
cmp.Equal(x.Config, y.Config) &&
cmp.Equal(x.Hooks, y.Hooks)
})
if !cmp.Equal(releases, test.RemainingReleases, rlsComparer) {
t.Errorf("Unexpected remaining releases. Diff %s", cmp.Diff(releases, test.RemainingReleases, rlsComparer))
}
if test.ResponseBody != "" {
if test.ResponseBody != response.Body.String() {
t.Errorf("Unexpected body response. Diff %s", cmp.Diff(test.ResponseBody, response.Body))
}
}
})
}
}

// derefReleases derefrences the releases in sotrage into an array
func derefReleases(storage *storage.Storage) []release.Release {
rls, _ := storage.ListReleases()
releases := make([]release.Release, len(rls))
for i := range rls {
releases[i] = *rls[i]
}
return releases
}

func createRelease(chartName, name, namespace string, version int, status release.Status) release.Release {
return release.Release{
Name: name,
Namespace: namespace,
Version: version,
Info: &release.Info{Status: status},
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: chartName,
},
Values: make(map[string]interface{}),
},
Config: make(map[string]interface{}),
}
}
29 changes: 25 additions & 4 deletions pkg/chart/fake/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import (
"net/http"

chartUtils "github.com/kubeapps/kubeapps/pkg/chart"
"k8s.io/helm/pkg/proto/hapi/chart"
chart3 "helm.sh/helm/v3/pkg/chart"
chart2 "k8s.io/helm/pkg/proto/hapi/chart"
"sigs.k8s.io/yaml"
)

type FakeChart struct{}
Expand All @@ -33,18 +35,37 @@ func (f *FakeChart) ParseDetails(data []byte) (*chartUtils.Details, error) {
}

func (f *FakeChart) GetChart(details *chartUtils.Details, netClient chartUtils.HTTPClient, requireV1Support bool) (*chartUtils.ChartMultiVersion, error) {
vals, err := getValues([]byte(details.Values))
if err != nil {
return nil, err
}
return &chartUtils.ChartMultiVersion{
Helm2Chart: &chart.Chart{
Metadata: &chart.Metadata{
Helm2Chart: &chart2.Chart{
Metadata: &chart2.Metadata{
Name: details.ChartName,
},
Values: &chart.Config{
Values: &chart2.Config{
Raw: details.Values,
},
},
Helm3Chart: &chart3.Chart{
Metadata: &chart3.Metadata{
Name: details.ChartName,
},
Values: vals,
},
}, nil
}

func getValues(raw []byte) (map[string]interface{}, error) {
values := make(map[string]interface{})
err := yaml.Unmarshal(raw, &values)
if err != nil {
return nil, err
}
return values, nil
}

func (f *FakeChart) InitNetClient(details *chartUtils.Details) (chartUtils.HTTPClient, error) {
return &http.Client{}, nil
}

0 comments on commit e946043

Please sign in to comment.