From 3f1325faf83287f32fa1bebbe8eb2bc6fc508fa7 Mon Sep 17 00:00:00 2001 From: "ys.achinta" Date: Mon, 22 Jun 2020 19:06:42 +0530 Subject: [PATCH] add list under an interface for easy testing --- cmd/service/service.go | 13 ++++--- pkg/api/chartloader.go | 18 ++++++++++ pkg/api/install_api_test.go | 37 ++++++-------------- pkg/api/installer.go | 23 ++++++++++--- pkg/api/list.go | 68 +++++++++++++++++++++++++++++++++++++ pkg/api/lister.go | 28 +++++++++++++++ pkg/api/service.go | 26 +++++--------- 7 files changed, 159 insertions(+), 54 deletions(-) create mode 100644 pkg/api/chartloader.go create mode 100644 pkg/api/list.go create mode 100644 pkg/api/lister.go diff --git a/cmd/service/service.go b/cmd/service/service.go index 375f9c4be..4221bf38d 100644 --- a/cmd/service/service.go +++ b/cmd/service/service.go @@ -13,19 +13,22 @@ import ( ) func main() { - app := servercontext.NewApp() - startServer(app) + servercontext.NewApp() + startServer() } -func startServer(appconfig *servercontext.Application) { +func startServer() { router := http.NewServeMux() //TODO: use gorilla mux and add middleware to write content type and other headers app := servercontext.App() logger.Setup("debug") - actionInstall := action.NewInstall(app.ActionConfig) - service := api.NewService(app.Config, new(action.ChartPathOptions), api.NewInstaller(actionInstall)) + service := api.NewService(app.Config, + new(action.ChartPathOptions), + api.NewInstall(action.NewInstall(app.ActionConfig)), + api.NewList(action.NewList(app.ActionConfig))) + router.Handle("/ping", ping.Handler()) router.Handle("/list", list.Handler()) router.Handle("/install", api.Install(service)) diff --git a/pkg/api/chartloader.go b/pkg/api/chartloader.go new file mode 100644 index 000000000..7887e1ed8 --- /dev/null +++ b/pkg/api/chartloader.go @@ -0,0 +1,18 @@ +package api + +import ( + "github.com/stretchr/testify/mock" + "helm.sh/helm/v3/pkg/cli" +) + +type chartloader interface { + LocateChart(name string, settings *cli.EnvSettings) (string, error) +} + +type MockChartLoader struct{ mock.Mock } + +func (m *MockChartLoader) LocateChart(name string, settings *cli.EnvSettings) (string, error) { + args := m.Called(name, settings) + return args.String(0), args.Error(1) +} + diff --git a/pkg/api/install_api_test.go b/pkg/api/install_api_test.go index 72961e8c2..0ccafa053 100644 --- a/pkg/api/install_api_test.go +++ b/pkg/api/install_api_test.go @@ -14,7 +14,6 @@ import ( "gotest.tools/assert" "helm.sh/helm/v3/pkg/api" "helm.sh/helm/v3/pkg/api/logger" - "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/release" ) @@ -23,8 +22,9 @@ type InstallerTestSuite struct { suite.Suite recorder *httptest.ResponseRecorder server *httptest.Server - mockInstaller *mockInstaller - mockChartLoader *mockChartLoader + mockInstall *api.MockInstall + mockChartLoader *api.MockChartLoader + mockList *api.MockList appConfig *cli.EnvSettings } @@ -34,13 +34,14 @@ func (s *InstallerTestSuite) SetupSuite() { func (s *InstallerTestSuite) SetupTest() { s.recorder = httptest.NewRecorder() - s.mockInstaller = new(mockInstaller) - s.mockChartLoader = new(mockChartLoader) + s.mockInstall = new(api.MockInstall) + s.mockChartLoader = new(api.MockChartLoader) + s.mockList = new(api.MockList) s.appConfig = &cli.EnvSettings{ RepositoryConfig: "./testdata/helm", PluginsDirectory: "./testdata/helm/plugin", } - service := api.NewService(s.appConfig, s.mockChartLoader, s.mockInstaller) + service := api.NewService(s.appConfig, s.mockChartLoader, s.mockInstall, s.mockList) handler := api.Install(service) s.server = httptest.NewServer(handler) } @@ -54,11 +55,11 @@ func (s *InstallerTestSuite) TestShouldReturnDeployedStatusOnSuccessfulInstall() req, _ := http.NewRequest("POST", fmt.Sprintf("%s/install", s.server.URL), strings.NewReader(body)) s.mockChartLoader.On("LocateChart", chartName, s.appConfig).Return("./testdata/albatross", nil) icfg := api.InstallConfig{ChartName: chartName, Name: "redis-v5", Namespace: "something"} - s.mockInstaller.On("SetConfig", icfg) + s.mockInstall.On("SetConfig", icfg) release := &release.Release{Info: &release.Info{Status: release.StatusDeployed}} var vals map[string]interface{} //TODO: pass chart object and verify values present testdata chart yml - s.mockInstaller.On("Run", mock.AnythingOfType("*chart.Chart"), vals).Return(release, nil) + s.mockInstall.On("Run", mock.AnythingOfType("*chart.Chart"), vals).Return(release, nil) resp, err := http.DefaultClient.Do(req) @@ -67,7 +68,7 @@ func (s *InstallerTestSuite) TestShouldReturnDeployedStatusOnSuccessfulInstall() respBody, _ := ioutil.ReadAll(resp.Body) assert.Equal(s.T(), expectedResponse, string(respBody)) require.NoError(s.T(), err) - s.mockInstaller.AssertExpectations(s.T()) + s.mockInstall.AssertExpectations(s.T()) s.mockChartLoader.AssertExpectations(s.T()) } @@ -78,21 +79,3 @@ func (s *InstallerTestSuite) TearDownTest() { func TestInstallAPI(t *testing.T) { suite.Run(t, new(InstallerTestSuite)) } - -type mockInstaller struct{ mock.Mock } - -func (m *mockInstaller) SetConfig(cfg api.InstallConfig) { - m.Called(cfg) -} - -func (m *mockInstaller) Run(c *chart.Chart, vals map[string]interface{}) (*release.Release, error) { - args := m.Called(c, vals) - return args.Get(0).(*release.Release), args.Error(1) -} - -type mockChartLoader struct{ mock.Mock } - -func (m *mockChartLoader) LocateChart(name string, settings *cli.EnvSettings) (string, error) { - args := m.Called(name, settings) - return args.String(0), args.Error(1) -} diff --git a/pkg/api/installer.go b/pkg/api/installer.go index 07a6402c1..1cf3eb6ca 100644 --- a/pkg/api/installer.go +++ b/pkg/api/installer.go @@ -1,24 +1,37 @@ package api import ( + "github.com/stretchr/testify/mock" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/release" ) -type Installer struct { +type install struct { *action.Install } -type runner interface { +type Installer interface { Run(*chart.Chart, map[string]interface{}) (*release.Release, error) + SetConfig(InstallConfig) } -func (i *Installer) SetConfig(cfg InstallConfig) { +func (i *install) SetConfig(cfg InstallConfig) { i.ReleaseName = cfg.Name i.Namespace = cfg.Namespace } -func NewInstaller(ai *action.Install) *Installer { - return &Installer{ai} +func NewInstall(ai *action.Install) *install { + return &install{ai} +} + +type MockInstall struct{ mock.Mock } + +func (m *MockInstall) SetConfig(cfg InstallConfig) { + m.Called(cfg) +} + +func (m *MockInstall) Run(c *chart.Chart, vals map[string]interface{}) (*release.Release, error) { + args := m.Called(c, vals) + return args.Get(0).(*release.Release), args.Error(1) } diff --git a/pkg/api/list.go b/pkg/api/list.go new file mode 100644 index 000000000..782cde97c --- /dev/null +++ b/pkg/api/list.go @@ -0,0 +1,68 @@ +package api + +import ( + "encoding/json" + "helm.sh/helm/v3/pkg/api/logger" + "net/http" +) + +type ListRequest struct { + RequestID string +} + +type ListResponse struct { + Error string `json:"error,omitempty"` + Data []HelmRelease +} + +type HelmRelease struct { + Release string `json:"release"` + Namespace string `json:"namespace"` +} + +func Handler(svc Service) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + var response ListResponse + var request ListRequest + decoder := json.NewDecoder(r.Body) + decoder.UseNumber() + if err := decoder.Decode(&request); err != nil { + response.Error = err.Error() + logger.Errorf("[List] error decoding request: %v", err) + w.WriteHeader(http.StatusBadRequest) + return + } + defer r.Body.Close() + + request.RequestID = r.Header.Get("Request-Id") + + svc.lister.SetStateMask() + res, err := svc.lister.Run() + + if err != nil { + response.Error = err.Error() + logger.Errorf("[List] error while installing chart: %v", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + var helmReleases []HelmRelease + for _, eachRes := range res { + r := HelmRelease{Release: eachRes.Name, Namespace: eachRes.Namespace} + helmReleases = append(helmReleases, r) + } + response = ListResponse{"", helmReleases} + payload, err := json.Marshal(response) + if err != nil { + response.Error = err.Error() + logger.Errorf("[List] error writing response %v", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + w.Write(payload) + }) +} \ No newline at end of file diff --git a/pkg/api/lister.go b/pkg/api/lister.go new file mode 100644 index 000000000..1abad4542 --- /dev/null +++ b/pkg/api/lister.go @@ -0,0 +1,28 @@ +package api + +import ( + "github.com/stretchr/testify/mock" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/release" +) + +type list struct { + *action.List +} + +type lister interface { + Run() ([]*release.Release, error) + SetStateMask() +} + +func NewList(action *action.List) *list{ + return &list{action} +} + + +type MockList struct{ mock.Mock } + +func (m *MockList) Run() ([]*release.Release, error) { + args := m.Called() + return args.Get(0).([]*release.Release), args.Error(1) +} \ No newline at end of file diff --git a/pkg/api/service.go b/pkg/api/service.go index 3b58b6cd8..93241a8b0 100644 --- a/pkg/api/service.go +++ b/pkg/api/service.go @@ -8,22 +8,13 @@ import ( "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/cli" - "helm.sh/helm/v3/pkg/release" _ "k8s.io/client-go/plugin/pkg/client/auth" ) -type installer interface { - SetConfig(InstallConfig) - Run(*chart.Chart, map[string]interface{}) (*release.Release, error) -} - -type chartloader interface { - LocateChart(name string, settings *cli.EnvSettings) (string, error) -} - type Service struct { settings *cli.EnvSettings - installer + Installer + lister chartloader } @@ -73,8 +64,8 @@ func (s Service) loadChart(chartName string) (*chart.Chart, error) { } func (s Service) installChart(icfg InstallConfig, ch *chart.Chart, vals chartValues) (*installResult, error) { - s.installer.SetConfig(icfg) - release, err := s.installer.Run(ch, vals) + s.Installer.SetConfig(icfg) + release, err := s.Installer.Run(ch, vals) if err != nil { return nil, fmt.Errorf("error in installing chart: %v", err) } @@ -85,10 +76,11 @@ func (s Service) installChart(icfg InstallConfig, ch *chart.Chart, vals chartVal return result, nil } -func NewService(settings *cli.EnvSettings, cl chartloader, i installer) Service { +func NewService(settings *cli.EnvSettings, cl chartloader, i Installer, l lister) Service { return Service{ - settings: settings, - chartloader: cl, - installer: i, + settings, + i, + l, + cl, } }