Skip to content

Commit

Permalink
[feat]: link charts to dashboard (#95)
Browse files Browse the repository at this point in the history
Signed-off-by: kevin <[email protected]>
  • Loading branch information
kevin6025 authored Jul 7, 2023
1 parent 1f8195e commit 96f3bd4
Show file tree
Hide file tree
Showing 27 changed files with 677 additions and 61 deletions.
1 change: 1 addition & 0 deletions cmd/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func runMigration(_ *cobra.Command, _ []string) error {
migrator.AddMigration(dbpkg.NewMigration(&model.Preference{}))
migrator.AddMigration(dbpkg.NewMigration(&model.Dashboard{}))
migrator.AddMigration(dbpkg.NewMigration(&model.Chart{}))
migrator.AddMigration(dbpkg.NewMigration(&model.Link{}))
migrator.AddMigration(dbpkg.NewMigration(&model.Team{}))
migrator.AddMigration(dbpkg.NewMigration(&model.TeamMember{}))
migrator.AddMigration(dbpkg.NewMigration(&model.Component{}))
Expand Down
19 changes: 16 additions & 3 deletions http/api/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ func NewChartAPI(deps *depspkg.API) *ChartAPI {
}

// CreateChart creates a new chart.
func (api *ChartAPI) CreateChart(c *gin.Context) { //nolint:dupl
func (api *ChartAPI) CreateChart(c *gin.Context) {
var chartJSON datatypes.JSON
if err := c.ShouldBind(&chartJSON); err != nil {
httppkg.Error(c, err)
return
}
chart := &model.Chart{
Config: chartJSON,
Model: chartJSON,
}
chart.ReadMeta()
ctx := c.Request.Context()
Expand All @@ -68,7 +68,7 @@ func (api *ChartAPI) UpdateChart(c *gin.Context) {
return
}
chart := &model.Chart{
Config: chartJSON,
Model: chartJSON,
}
chart.ReadMeta()
ctx := c.Request.Context()
Expand Down Expand Up @@ -107,3 +107,16 @@ func (api *ChartAPI) DeleteChartByUID(c *gin.Context) {
}
httppkg.OK(c, "Chart deleted")
}

// GetChartByUID returns chart by given uid.
func (api *ChartAPI) GetChartByUID(c *gin.Context) {
uid := c.Param(constant.UID)
chart, err := api.deps.ChartSrv.GetChartByUID(c.Request.Context(), uid)
if err != nil {
httppkg.Error(c, err)
return
}
httppkg.OK(c, gin.H{
"model": chart.Model,
})
}
50 changes: 50 additions & 0 deletions http/api/chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,53 @@ func TestChartAPI_DeleteChartByUID(t *testing.T) {
})
}
}

func TestChartAPI_GetChartByUID(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

chartSrv := service.NewMockChartService(ctrl)
r := gin.New()
api := NewChartAPI(&deps.API{
ChartSrv: chartSrv,
})
r.GET("/chart/:uid", api.GetChartByUID)

cases := []struct {
name string
prepare func()
assert func(resp *httptest.ResponseRecorder)
}{
{
name: "get chart failure",
prepare: func() {
chartSrv.EXPECT().GetChartByUID(gomock.Any(), "1234").Return(nil, fmt.Errorf("err"))
},
assert: func(resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusInternalServerError, resp.Code)
},
},
{
name: "get chart successfully",
prepare: func() {
chartSrv.EXPECT().GetChartByUID(gomock.Any(), "1234").Return(&model.Chart{}, nil)
},
assert: func(resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusOK, resp.Code)
},
},
}
for _, tt := range cases {
tt := tt
t.Run(tt.name, func(_ *testing.T) {
req, _ := http.NewRequestWithContext(context.TODO(), http.MethodGet, "/chart/1234", http.NoBody)
req.Header.Set("content-type", "application/json")
resp := httptest.NewRecorder()
if tt.prepare != nil {
tt.prepare()
}
r.ServeHTTP(resp, req)
tt.assert(resp)
})
}
}
12 changes: 11 additions & 1 deletion http/api/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func NewDashboardAPI(deps *depspkg.API) *DashboardAPI {
}

// CreateDashboard creates a new dashboard.
func (api *DashboardAPI) CreateDashboard(c *gin.Context) { //nolint:dupl
func (api *DashboardAPI) CreateDashboard(c *gin.Context) {
var dashboardJSON datatypes.JSON
if err := c.ShouldBind(&dashboardJSON); err != nil {
httppkg.Error(c, err)
Expand All @@ -63,6 +63,11 @@ func (api *DashboardAPI) CreateDashboard(c *gin.Context) { //nolint:dupl
httppkg.Error(c, err)
return
}
// try add chart links if use chart repos in dashboard config
if err = api.deps.ChartSrv.LinkChartsToDashboard(ctx, dashboard); err != nil {
httppkg.Error(c, err)
return
}
httppkg.OK(c, uid)
}

Expand All @@ -82,6 +87,11 @@ func (api *DashboardAPI) UpdateDashboard(c *gin.Context) {
httppkg.Error(c, err)
return
}
// try add chart links if use chart repos in dashboard config
if err := api.deps.ChartSrv.LinkChartsToDashboard(ctx, dashboard); err != nil {
httppkg.Error(c, err)
return
}
httppkg.OK(c, "Dashboard updated")
}

Expand Down
28 changes: 28 additions & 0 deletions http/api/dashboard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ func TestDashboardAPI_CreateDashboard(t *testing.T) {
defer ctrl.Finish()

dashboardSrv := service.NewMockDashboardService(ctrl)
chartSrv := service.NewMockChartService(ctrl)
r := gin.New()
api := NewDashboardAPI(&deps.API{
DashboardSrv: dashboardSrv,
ChartSrv: chartSrv,
})
r.POST("/dashboard", api.CreateDashboard)
body := encoding.JSONMarshal(&model.Dashboard{Title: "test"})
Expand Down Expand Up @@ -77,11 +79,23 @@ func TestDashboardAPI_CreateDashboard(t *testing.T) {
assert.Equal(t, http.StatusInternalServerError, resp.Code)
},
},
{
name: "link charts to dashboard failure",
body: bytes.NewBuffer(encoding.JSONMarshal(&model.Dashboard{Config: body})),
prepare: func() {
dashboardSrv.EXPECT().CreateDashboard(gomock.Any(), gomock.Any()).Return("1234", nil)
chartSrv.EXPECT().LinkChartsToDashboard(gomock.Any(), gomock.Any()).Return(fmt.Errorf("err"))
},
assert: func(resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusInternalServerError, resp.Code)
},
},
{
name: "create dashboard successfully",
body: bytes.NewBuffer(encoding.JSONMarshal(&model.Dashboard{Config: body})),
prepare: func() {
dashboardSrv.EXPECT().CreateDashboard(gomock.Any(), gomock.Any()).Return("1234", nil)
chartSrv.EXPECT().LinkChartsToDashboard(gomock.Any(), gomock.Any()).Return(nil)
},
assert: func(resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusOK, resp.Code)
Expand Down Expand Up @@ -109,9 +123,11 @@ func TestDashboardAPI_UpdateDashboard(t *testing.T) {
defer ctrl.Finish()

dashboardSrv := service.NewMockDashboardService(ctrl)
chartSrv := service.NewMockChartService(ctrl)
r := gin.New()
api := NewDashboardAPI(&deps.API{
DashboardSrv: dashboardSrv,
ChartSrv: chartSrv,
})
r.PUT("/dashboard", api.UpdateDashboard)
body := encoding.JSONMarshal(&model.Dashboard{})
Expand Down Expand Up @@ -139,11 +155,23 @@ func TestDashboardAPI_UpdateDashboard(t *testing.T) {
assert.Equal(t, http.StatusInternalServerError, resp.Code)
},
},
{
name: "link chart to dashboard failure",
body: bytes.NewBuffer(body),
prepare: func() {
dashboardSrv.EXPECT().UpdateDashboard(gomock.Any(), gomock.Any()).Return(nil)
chartSrv.EXPECT().LinkChartsToDashboard(gomock.Any(), gomock.Any()).Return(fmt.Errorf("err"))
},
assert: func(resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusInternalServerError, resp.Code)
},
},
{
name: "update dashboard successfully",
body: bytes.NewBuffer(body),
prepare: func() {
dashboardSrv.EXPECT().UpdateDashboard(gomock.Any(), gomock.Any()).Return(nil)
chartSrv.EXPECT().LinkChartsToDashboard(gomock.Any(), gomock.Any()).Return(nil)
},
assert: func(resp *httptest.ResponseRecorder) {
assert.Equal(t, http.StatusOK, resp.Code)
Expand Down
2 changes: 2 additions & 0 deletions http/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ func (r *Router) RegisterRouters() {
middleware.Authorize(r.deps, accesscontrol.ViewerAccessResource, accesscontrol.Write, r.chartAPI.UpdateChart)...)
router.DELETE("/charts/:uid",
middleware.Authorize(r.deps, accesscontrol.ViewerAccessResource, accesscontrol.Write, r.chartAPI.DeleteChartByUID)...)
router.GET("/charts/:uid",
middleware.Authorize(r.deps, accesscontrol.ViewerAccessResource, accesscontrol.Read, r.chartAPI.GetChartByUID)...)
router.GET("/charts",
middleware.Authorize(r.deps, accesscontrol.ViewerAccessResource, accesscontrol.Read, r.chartAPI.SearchCharts)...)

Expand Down
7 changes: 6 additions & 1 deletion http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ import (
"github.com/lindb/linsight/config"
)

// for testing.
var (
listenFn = net.Listen
)

// Server represents http server based on gin.
type Server struct {
engine *gin.Engine
Expand Down Expand Up @@ -75,7 +80,7 @@ func (s *Server) initialize() {
// Run runs http server.
func (s *Server) Run() error {
s.server.Handler = s.engine
listen, err := net.Listen("tcp", s.addr)
listen, err := listenFn("tcp", s.addr)
if err != nil {
return err
}
Expand Down
48 changes: 48 additions & 0 deletions http/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to LinDB under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. LinDB licenses this file to you 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 http

import (
"fmt"
"net"
"testing"

"github.com/stretchr/testify/assert"

"github.com/lindb/linsight/config"
)

func TestHTTPServce(t *testing.T) {
defer func() {
listenFn = net.Listen
}()
s := NewServer(&config.HTTP{Port: 19200})
assert.NotNil(t, s.GetEngine())
listenFn = func(_, _ string) (net.Listener, error) {
return nil, fmt.Errorf("err")
}
assert.Error(t, s.Run())

listenFn = func(_, _ string) (net.Listener, error) {
return nil, nil
}
assert.Panics(t, func() {
_ = s.Run()
assert.True(t, false)
})
}
22 changes: 15 additions & 7 deletions http/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,31 @@
package http

import (
"fmt"
"io/fs"
"net/http"
"path"

"github.com/gin-gonic/gin"
httpcommon "github.com/lindb/common/pkg/http"
"github.com/lindb/common/pkg/logger"

"github.com/lindb/linsight"
"github.com/lindb/linsight/constant"
httppkg "github.com/lindb/linsight/pkg/http"
"github.com/lindb/linsight/pkg/util"
)

// for testing
var (
fsSubFn = fs.Sub
)

var httpLogger = logger.GetLogger("HTTP", "Static")

// handleStatic handles static resource request.
func handleStatic(e *gin.Engine) {
// server static file
staticFS, err := fs.Sub(linsight.StaticFS, "web/static")
staticFS, err := fsSubFn(linsight.StaticFS, "web/static")
if err != nil {
panic(err)
} else {
Expand All @@ -49,21 +57,21 @@ func handleStatic(e *gin.Engine) {
}
if httppkg.IsLoginPage(c) {
// check if use already signed
_, isSigned := c.Get(constant.LinSightSigned)
if isSigned {
signedUser := util.GetUser(c.Request.Context())
if signedUser != nil {
httpcommon.Redirect(c, constant.HomePage)
c.Abort()
return
}
}
file, err := httpFS.Open(path.Join(urlPrefix, c.Request.URL.Path))
filePath := path.Join(urlPrefix, c.Request.URL.Path)
file, err := httpFS.Open(filePath)
if err == nil {
_ = file.Close()
fileserver.ServeHTTP(c.Writer, c.Request)
c.Abort()
} else {
// FIXME: add log
fmt.Println(err)
httpLogger.Error("static resource not found", logger.String("resource", filePath), logger.Error(err))
}
}
}
Expand Down
Loading

0 comments on commit 96f3bd4

Please sign in to comment.