package navtreeimpl import ( "net/http" "testing" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" ac "github.com/grafana/grafana/pkg/services/accesscontrol" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/navtree" "github.com/grafana/grafana/pkg/services/pluginsettings" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" "github.com/stretchr/testify/require" ) func TestAddAppLinks(t *testing.T) { httpReq, _ := http.NewRequest(http.MethodGet, "", nil) reqCtx := &models.ReqContext{SignedInUser: &user.SignedInUser{}, Context: &web.Context{Req: httpReq}} permissions := []ac.Permission{ {Action: plugins.ActionAppAccess, Scope: "*"}, } testApp1 := plugins.PluginDTO{ JSONData: plugins.JSONData{ ID: "test-app1", Name: "Test app1 name", Type: plugins.App, Includes: []*plugins.Includes{ { Name: "Hello", Path: "/a/test-app1/catalog", Type: "page", AddToNav: true, DefaultNav: true, }, { Name: "Hello", Path: "/a/test-app1/page2", Type: "page", AddToNav: true, }, }, }, } testApp2 := plugins.PluginDTO{ JSONData: plugins.JSONData{ ID: "test-app2", Name: "Test app2 name", Type: plugins.App, Includes: []*plugins.Includes{ { Name: "Hello", Path: "/a/quick-app/catalog", Type: "page", AddToNav: true, DefaultNav: true, }, }, }, } pluginSettings := pluginsettings.FakePluginSettings{Plugins: map[string]*pluginsettings.DTO{ testApp1.ID: {ID: 0, OrgID: 1, PluginID: testApp1.ID, PluginVersion: "1.0.0", Enabled: true}, testApp2.ID: {ID: 0, OrgID: 1, PluginID: testApp2.ID, PluginVersion: "1.0.0", Enabled: true}, }} service := ServiceImpl{ log: log.New("navtree"), cfg: setting.NewCfg(), accessControl: accesscontrolmock.New().WithPermissions(permissions), pluginSettings: &pluginSettings, features: featuremgmt.WithFeatures(), pluginStore: plugins.FakePluginStore{ PluginList: []plugins.PluginDTO{testApp1, testApp2}, }, } t.Run("Should add enabled apps with pages", func(t *testing.T) { treeRoot := navtree.NavTreeRoot{} err := service.addAppLinks(&treeRoot, reqCtx) require.NoError(t, err) require.Equal(t, "Test app1 name", treeRoot.Children[0].Text) require.Equal(t, "/a/test-app1/catalog", treeRoot.Children[0].Url) require.Equal(t, "/a/test-app1/page2", treeRoot.Children[0].Children[1].Url) }) t.Run("Should move apps to Apps category when topnav is enabled", func(t *testing.T) { service.features = featuremgmt.WithFeatures(featuremgmt.FlagTopnav) treeRoot := navtree.NavTreeRoot{} err := service.addAppLinks(&treeRoot, reqCtx) require.NoError(t, err) require.Equal(t, "Apps", treeRoot.Children[0].Text) require.Equal(t, "Test app1 name", treeRoot.Children[0].Children[0].Text) }) t.Run("Should move apps that have specific nav id configured to correct section", func(t *testing.T) { service.features = featuremgmt.WithFeatures(featuremgmt.FlagTopnav) service.navigationAppConfig = map[string]NavigationAppConfig{ "test-app1": {SectionID: navtree.NavIDAdmin}, } treeRoot := navtree.NavTreeRoot{} treeRoot.AddSection(&navtree.NavLink{ Id: navtree.NavIDAdmin, }) err := service.addAppLinks(&treeRoot, reqCtx) require.NoError(t, err) require.Equal(t, "plugin-page-test-app1", treeRoot.Children[0].Children[0].Id) }) t.Run("Should add monitoring section if plugin exists that wants to live there", func(t *testing.T) { service.features = featuremgmt.WithFeatures(featuremgmt.FlagTopnav) service.navigationAppConfig = map[string]NavigationAppConfig{ "test-app1": {SectionID: navtree.NavIDMonitoring}, } treeRoot := navtree.NavTreeRoot{} err := service.addAppLinks(&treeRoot, reqCtx) require.NoError(t, err) require.Equal(t, "Monitoring", treeRoot.Children[0].Text) require.Equal(t, "Test app1 name", treeRoot.Children[0].Children[0].Text) }) t.Run("Should add Alerts and incidents section if plugin exists that wants to live there", func(t *testing.T) { service.features = featuremgmt.WithFeatures(featuremgmt.FlagTopnav) service.navigationAppConfig = map[string]NavigationAppConfig{ "test-app1": {SectionID: navtree.NavIDAlertsAndIncidents}, } treeRoot := navtree.NavTreeRoot{} treeRoot.AddSection(&navtree.NavLink{Id: navtree.NavIDAlerting, Text: "Alerting"}) err := service.addAppLinks(&treeRoot, reqCtx) require.NoError(t, err) require.Equal(t, "Alerts & incidents", treeRoot.Children[0].Text) require.Equal(t, "Alerting", treeRoot.Children[0].Children[0].Text) require.Equal(t, "Test app1 name", treeRoot.Children[0].Children[1].Text) }) t.Run("Should be able to control app sort order with SortWeight", func(t *testing.T) { service.features = featuremgmt.WithFeatures(featuremgmt.FlagTopnav) service.navigationAppConfig = map[string]NavigationAppConfig{ "test-app2": {SectionID: navtree.NavIDMonitoring, SortWeight: 1}, "test-app1": {SectionID: navtree.NavIDMonitoring, SortWeight: 2}, } treeRoot := navtree.NavTreeRoot{} err := service.addAppLinks(&treeRoot, reqCtx) treeRoot.Sort() require.NoError(t, err) require.Equal(t, "Test app2 name", treeRoot.Children[0].Children[0].Text) require.Equal(t, "Test app1 name", treeRoot.Children[0].Children[1].Text) }) } func TestReadingNavigationSettings(t *testing.T) { t.Run("Should include defaults", func(t *testing.T) { service := ServiceImpl{ cfg: setting.NewCfg(), } _, _ = service.cfg.Raw.NewSection("navigation.apps") service.readNavigationSettings() require.Equal(t, "monitoring", service.navigationAppConfig["grafana-k8s-app"].SectionID) }) t.Run("Can add additional overrides via ini system", func(t *testing.T) { service := ServiceImpl{ cfg: setting.NewCfg(), } sec, _ := service.cfg.Raw.NewSection("navigation.apps") _, _ = sec.NewKey("grafana-k8s-app", "dashboards") _, _ = sec.NewKey("other-app", "admin 12") service.readNavigationSettings() require.Equal(t, "dashboards", service.navigationAppConfig["grafana-k8s-app"].SectionID) require.Equal(t, "admin", service.navigationAppConfig["other-app"].SectionID) require.Equal(t, int64(0), service.navigationAppConfig["grafana-k8s-app"].SortWeight) require.Equal(t, int64(12), service.navigationAppConfig["other-app"].SortWeight) }) }