From 7e2840bd32f140de4d2122f31c4dc25bb48493e6 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Fri, 7 Feb 2020 17:16:48 -0500 Subject: [PATCH] add Request interface to make plugin testing easier Signed-off-by: Wayne Witzel III --- build.go | 6 +++++- changelogs/unreleased/645-wwitzel3 | 3 +++ cmd/octant-sample-plugin/main.go | 6 +++--- pkg/plugin/service/handler.go | 4 ++-- pkg/plugin/service/router.go | 28 +++++++++++++++++++++------- pkg/plugin/service/router_test.go | 12 ++++++------ 6 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 changelogs/unreleased/645-wwitzel3 diff --git a/build.go b/build.go index dc785303c9..63326973c4 100644 --- a/build.go +++ b/build.go @@ -236,7 +236,11 @@ func installTestPlugin() { dir := pluginDir() log.Printf("Plugin path: %s", dir) os.MkdirAll(dir, 0755) - pluginFile := fmt.Sprintf("%s/octant-sample-plugin", dir) + filename := "octant-sample-plugin" + if runtime.GOOS == "windows" { + filename = "octant-sample-plugin.exe" + } + pluginFile := filepath.Join(dir, filename) runCmd("go", nil, "build", "-o", pluginFile, "github.com/vmware-tanzu/octant/cmd/octant-sample-plugin") } diff --git a/changelogs/unreleased/645-wwitzel3 b/changelogs/unreleased/645-wwitzel3 new file mode 100644 index 0000000000..fecb894352 --- /dev/null +++ b/changelogs/unreleased/645-wwitzel3 @@ -0,0 +1,3 @@ +Plugins, service.Request is now an interface. This is a breaking API change. + - HandlerFunc now takes this new interface which allows for fakes/mocks during unit testing. + - Path proprety is now accessed via Path() diff --git a/cmd/octant-sample-plugin/main.go b/cmd/octant-sample-plugin/main.go index 0d1a7ce79a..383526a833 100644 --- a/cmd/octant-sample-plugin/main.go +++ b/cmd/octant-sample-plugin/main.go @@ -181,10 +181,10 @@ func initRoutes(router *service.Router) { return cardList } - router.HandleFunc("*", func(request *service.Request) (component.ContentResponse, error) { + router.HandleFunc("*", func(request service.Request) (component.ContentResponse, error) { // For each page, generate two tabs with a some content. - component1 := gen("Tab 1", "tab1", request.Path) - component2 := gen("Tab 2", "tab2", request.Path) + component1 := gen("Tab 1", "tab1", request.Path()) + component2 := gen("Tab 2", "tab2", request.Path()) contentResponse := component.NewContentResponse(component.TitleFromString("Example")) contentResponse.Add(component1, component2) diff --git a/pkg/plugin/service/handler.go b/pkg/plugin/service/handler.go index 4962d29f82..dd30b673a4 100644 --- a/pkg/plugin/service/handler.go +++ b/pkg/plugin/service/handler.go @@ -139,10 +139,10 @@ func (p *Handler) Content(ctx context.Context, contentPath string) (component.Co return component.ContentResponse{}, nil } - request := &Request{ + request := &request{ baseRequest: newBaseRequest(ctx, p.name), dashboardClient: p.dashboardClient, - Path: contentPath, + path: contentPath, } return handlerFunc(request) diff --git a/pkg/plugin/service/router.go b/pkg/plugin/service/router.go index 45df0a4bd0..399a91e744 100644 --- a/pkg/plugin/service/router.go +++ b/pkg/plugin/service/router.go @@ -1,32 +1,46 @@ package service import ( + "context" + "github.com/gobwas/glob" "github.com/vmware-tanzu/octant/pkg/view/component" ) // HandleFunc is a function that generates a content response. -type HandleFunc func(request *Request) (component.ContentResponse, error) +type HandleFunc func(request Request) (component.ContentResponse, error) + +type Request interface { + Context() context.Context + DashboardClient() Dashboard + Path() string +} + +var _ Request = (*request)(nil) // Request represents a path request from Octant. It will always be a // GET style request with a path. -type Request struct { +type request struct { baseRequest dashboardClient Dashboard - // Path is path that Octant is requesting. It is scoped to the plugin. - // i.e. If Octant wants to render /content/plugin/foo, Path will be - // `/foo`. - Path string + path string } // DashboardClient returns a dashboard client for the request. -func (r *Request) DashboardClient() Dashboard { +func (r *request) DashboardClient() Dashboard { return r.dashboardClient } +// Path is path that Octant is requesting. It is scoped to the plugin. +// i.e. If Octant wants to render /content/plugin/foo, Path will be +// `/foo`. +func (r *request) Path() string { + return r.path +} + type route struct { path string glob glob.Glob diff --git a/pkg/plugin/service/router_test.go b/pkg/plugin/service/router_test.go index f223cff7b0..81c24a6e0e 100644 --- a/pkg/plugin/service/router_test.go +++ b/pkg/plugin/service/router_test.go @@ -21,16 +21,16 @@ func TestRouter_Match(t *testing.T) { } router := NewRouter() - router.HandleFunc("/nested1/nested2", func(request *Request) (component.ContentResponse, error) { + router.HandleFunc("/nested1/nested2", func(request Request) (component.ContentResponse, error) { return genContentResponse("nested2"), nil }) - router.HandleFunc("/nested1", func(request *Request) (component.ContentResponse, error) { + router.HandleFunc("/nested1", func(request Request) (component.ContentResponse, error) { return genContentResponse("nested1"), nil }) - router.HandleFunc("/glob*", func(request *Request) (component.ContentResponse, error) { + router.HandleFunc("/glob*", func(request Request) (component.ContentResponse, error) { return genContentResponse("glob"), nil }) - router.HandleFunc("/", func(request *Request) (component.ContentResponse, error) { + router.HandleFunc("/", func(request Request) (component.ContentResponse, error) { return genContentResponse("root"), nil }) @@ -81,10 +81,10 @@ func TestRouter_Match(t *testing.T) { } require.True(t, ok) - request := &Request{ + request := &request{ baseRequest: newBaseRequest(context.Background(), "plugin-name"), dashboardClient: nil, - Path: test.path, + path: test.path, } got, err := handleFunc(request) require.NoError(t, err)