| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | package dashboards | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2024-04-08 15:47:34 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/dtos" | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/components/simplejson" | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/db" | 
					
						
							| 
									
										
										
										
											2024-04-30 19:15:56 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2022-01-28 17:28:33 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/dashboardimport" | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/dashboards" | 
					
						
							| 
									
										
										
										
											2025-03-31 18:02:19 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/folder" | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/org" | 
					
						
							| 
									
										
										
										
											2022-12-08 00:03:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/org/orgimpl" | 
					
						
							| 
									
										
										
										
											2022-03-11 01:38:04 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/plugindashboards" | 
					
						
							| 
									
										
										
										
											2022-12-08 00:03:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/quota/quotaimpl" | 
					
						
							| 
									
										
										
										
											2023-01-31 18:04:55 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/search/model" | 
					
						
							| 
									
										
										
										
											2023-02-07 00:50:03 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest" | 
					
						
							| 
									
										
										
										
											2022-06-28 20:32:25 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							| 
									
										
										
										
											2022-12-08 00:03:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/user/userimpl" | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/tests/testinfra" | 
					
						
							| 
									
										
										
										
											2024-02-09 22:35:39 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/tests/testsuite" | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util" | 
					
						
							| 
									
										
										
										
											2024-04-08 15:47:34 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util/retryer" | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-09 22:35:39 +08:00
										 |  |  | func TestMain(m *testing.M) { | 
					
						
							|  |  |  | 	testsuite.Run(m) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 15:11:56 +08:00
										 |  |  | func TestIntegrationDashboardQuota(t *testing.T) { | 
					
						
							|  |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	// enable quota and set low dashboard quota
 | 
					
						
							|  |  |  | 	// Setup Grafana and its Database
 | 
					
						
							|  |  |  | 	dashboardQuota := int64(1) | 
					
						
							|  |  |  | 	dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ | 
					
						
							|  |  |  | 		DisableAnonymous:  true, | 
					
						
							|  |  |  | 		EnableQuota:       true, | 
					
						
							|  |  |  | 		DashboardOrgQuota: &dashboardQuota, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2022-01-20 18:10:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) | 
					
						
							|  |  |  | 	store, cfg := env.SQLStore, env.Cfg | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	// Create user
 | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	createUser(t, store, cfg, user.CreateUserCommand{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 		DefaultOrgRole: string(org.RoleAdmin), | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 		Password:       "admin", | 
					
						
							|  |  |  | 		Login:          "admin", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("when quota limit doesn't exceed, importing a dashboard should succeed", func(t *testing.T) { | 
					
						
							|  |  |  | 		// Import dashboard
 | 
					
						
							|  |  |  | 		dashboardDataOne, err := simplejson.NewJson([]byte(`{"title":"just testing"}`)) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		buf1 := &bytes.Buffer{} | 
					
						
							| 
									
										
										
										
											2022-01-28 17:28:33 +08:00
										 |  |  | 		err = json.NewEncoder(buf1).Encode(dashboardimport.ImportDashboardRequest{ | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 			Dashboard: dashboardDataOne, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/import", grafanaListedAddr) | 
					
						
							|  |  |  | 		// nolint:gosec
 | 
					
						
							|  |  |  | 		resp, err := http.Post(u, "application/json", buf1) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, resp.StatusCode) | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			err := resp.Body.Close() | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 		b, err := io.ReadAll(resp.Body) | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-03-11 01:38:04 +08:00
										 |  |  | 		dashboardDTO := &plugindashboards.PluginDashboard{} | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 		err = json.Unmarshal(b, dashboardDTO) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.EqualValues(t, 1, dashboardDTO.DashboardId) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("when quota limit exceeds importing a dashboard should fail", func(t *testing.T) { | 
					
						
							|  |  |  | 		dashboardDataOne, err := simplejson.NewJson([]byte(`{"title":"just testing"}`)) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		buf1 := &bytes.Buffer{} | 
					
						
							| 
									
										
										
										
											2022-01-28 17:28:33 +08:00
										 |  |  | 		err = json.NewEncoder(buf1).Encode(dashboardimport.ImportDashboardRequest{ | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 			Dashboard: dashboardDataOne, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/import", grafanaListedAddr) | 
					
						
							|  |  |  | 		// nolint:gosec
 | 
					
						
							|  |  |  | 		resp, err := http.Post(u, "application/json", buf1) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, resp.StatusCode) | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			err := resp.Body.Close() | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 		b, err := io.ReadAll(resp.Body) | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, resp.StatusCode) | 
					
						
							|  |  |  | 		require.JSONEq(t, `{"message":"Quota reached"}`, string(b)) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 07:21:39 +08:00
										 |  |  | func createUser(t *testing.T, db db.DB, cfg *setting.Cfg, cmd user.CreateUserCommand) int64 { | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	t.Helper() | 
					
						
							| 
									
										
										
										
											2022-06-07 21:49:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	cfg.AutoAssignOrg = true | 
					
						
							|  |  |  | 	cfg.AutoAssignOrgId = 1 | 
					
						
							| 
									
										
										
										
											2022-06-07 21:49:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 07:21:39 +08:00
										 |  |  | 	quotaService := quotaimpl.ProvideService(db, cfg) | 
					
						
							|  |  |  | 	orgService, err := orgimpl.ProvideService(db, cfg, quotaService) | 
					
						
							| 
									
										
										
										
											2022-12-08 00:03:22 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-04-30 19:15:56 +08:00
										 |  |  | 	usrSvc, err := userimpl.ProvideService( | 
					
						
							| 
									
										
										
										
											2024-09-26 07:21:39 +08:00
										 |  |  | 		db, orgService, cfg, nil, nil, tracing.InitializeTracerForTest(), | 
					
						
							| 
									
										
										
										
											2024-04-30 19:15:56 +08:00
										 |  |  | 		quotaService, supportbundlestest.NewFakeBundleService(), | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2022-12-08 00:03:22 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-04 00:01:23 +08:00
										 |  |  | 	u, err := usrSvc.Create(context.Background(), &cmd) | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-06-28 20:32:25 +08:00
										 |  |  | 	return u.ID | 
					
						
							| 
									
										
										
										
											2021-11-16 17:26:46 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 15:11:56 +08:00
										 |  |  | func TestIntegrationUpdatingProvisionionedDashboards(t *testing.T) { | 
					
						
							|  |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 	// Setup Grafana and its Database
 | 
					
						
							|  |  |  | 	dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ | 
					
						
							|  |  |  | 		DisableAnonymous: true, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	provDashboardsDir := filepath.Join(dir, "conf", "provisioning", "dashboards") | 
					
						
							|  |  |  | 	provDashboardsCfg := filepath.Join(provDashboardsDir, "dev.yaml") | 
					
						
							|  |  |  | 	blob := []byte(fmt.Sprintf(` | 
					
						
							|  |  |  | apiVersion: 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | providers: | 
					
						
							|  |  |  | - name: 'provisioned dashboards' | 
					
						
							|  |  |  |   type: file | 
					
						
							|  |  |  |   allowUiUpdates: false | 
					
						
							|  |  |  |   options: | 
					
						
							|  |  |  |    path: %s`, provDashboardsDir)) | 
					
						
							|  |  |  | 	err := os.WriteFile(provDashboardsCfg, blob, 0644) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 	input, err := os.ReadFile(filepath.Join("./home.json")) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	provDashboardFile := filepath.Join(provDashboardsDir, "home.json") | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 	err = os.WriteFile(provDashboardFile, input, 0644) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) | 
					
						
							|  |  |  | 	store, cfg := env.SQLStore, env.Cfg | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 	// Create user
 | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	createUser(t, store, cfg, user.CreateUserCommand{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 		DefaultOrgRole: string(org.RoleAdmin), | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 		Password:       "admin", | 
					
						
							|  |  |  | 		Login:          "admin", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 23:42:12 +08:00
										 |  |  | 	// give provisioner some time since we don't have a way to know when provisioning is complete
 | 
					
						
							|  |  |  | 	// TODO https://github.com/grafana/grafana/issues/85617
 | 
					
						
							|  |  |  | 	time.Sleep(1 * time.Second) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 	type errorResponseBody struct { | 
					
						
							|  |  |  | 		Message string `json:"message"` | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("when provisioned directory is not empty, dashboard should be created", func(t *testing.T) { | 
					
						
							|  |  |  | 		title := "Grafana Dev Overview & Home" | 
					
						
							| 
									
										
										
										
											2023-01-31 18:04:55 +08:00
										 |  |  | 		dashboardList := &model.HitList{} | 
					
						
							| 
									
										
										
										
											2024-04-08 15:47:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		retry := 0 | 
					
						
							|  |  |  | 		retries := 5 | 
					
						
							|  |  |  | 		// retry until the provisioned dashboard is ready
 | 
					
						
							|  |  |  | 		err := retryer.Retry(func() (retryer.RetrySignal, error) { | 
					
						
							|  |  |  | 			retry++ | 
					
						
							|  |  |  | 			u := fmt.Sprintf("http://admin:admin@%s/api/search?query=%s", grafanaListedAddr, url.QueryEscape(title)) | 
					
						
							|  |  |  | 			// nolint:gosec
 | 
					
						
							|  |  |  | 			resp, err := http.Get(u) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			assert.Equal(t, http.StatusOK, resp.StatusCode) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				err := resp.Body.Close() | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			b, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			err = json.Unmarshal(b, dashboardList) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			if dashboardList.Len() == 0 { | 
					
						
							|  |  |  | 				if retry >= retries { | 
					
						
							|  |  |  | 					return retryer.FuncError, fmt.Errorf("max retries exceeded") | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				t.Log("Dashboard is not ready", "retry", retry) | 
					
						
							|  |  |  | 				return retryer.FuncFailure, nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return retryer.FuncComplete, nil | 
					
						
							|  |  |  | 		}, retries, time.Millisecond*time.Duration(10), time.Second) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-04-08 15:47:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 		var dashboardUID string | 
					
						
							|  |  |  | 		var dashboardID int64 | 
					
						
							|  |  |  | 		for _, d := range *dashboardList { | 
					
						
							|  |  |  | 			dashboardUID = d.UID | 
					
						
							|  |  |  | 			dashboardID = d.ID | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		assert.Equal(t, int64(1), dashboardID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		testCases := []struct { | 
					
						
							|  |  |  | 			desc          string | 
					
						
							|  |  |  | 			dashboardData string | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 			expStatus     int | 
					
						
							|  |  |  | 			expErrReason  string | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 		}{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				desc:          "when updating provisioned dashboard using ID it should fail", | 
					
						
							|  |  |  | 				dashboardData: fmt.Sprintf(`{"title":"just testing", "id": %d, "version": 1}`, dashboardID), | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 				expStatus:     http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				expErrReason:  dashboards.ErrDashboardCannotSaveProvisionedDashboard.Reason, | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 				desc:          "when updating provisioned dashboard using UID it should fail", | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 				dashboardData: fmt.Sprintf(`{"title":"just testing", "uid": %q, "version": 1}`, dashboardUID), | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 				expStatus:     http.StatusBadRequest, | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				expErrReason:  dashboards.ErrDashboardCannotSaveProvisionedDashboard.Reason, | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				desc:          "when updating dashboard using unknown ID, it should fail", | 
					
						
							|  |  |  | 				dashboardData: `{"title":"just testing", "id": 42, "version": 1}`, | 
					
						
							|  |  |  | 				expStatus:     http.StatusNotFound, | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				expErrReason:  dashboards.ErrDashboardNotFound.Reason, | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				desc:          "when updating dashboard using unknown UID, it should succeed", | 
					
						
							|  |  |  | 				dashboardData: `{"title":"just testing", "uid": "unknown", "version": 1}`, | 
					
						
							|  |  |  | 				expStatus:     http.StatusOK, | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for _, tc := range testCases { | 
					
						
							|  |  |  | 			t.Run(tc.desc, func(t *testing.T) { | 
					
						
							|  |  |  | 				u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr) | 
					
						
							|  |  |  | 				// nolint:gosec
 | 
					
						
							|  |  |  | 				dashboardData, err := simplejson.NewJson([]byte(tc.dashboardData)) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				buf := &bytes.Buffer{} | 
					
						
							| 
									
										
										
										
											2023-01-18 20:52:41 +08:00
										 |  |  | 				err = json.NewEncoder(buf).Encode(dashboards.SaveDashboardCommand{ | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 					Dashboard: dashboardData, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// nolint:gosec
 | 
					
						
							|  |  |  | 				resp, err := http.Post(u, "application/json", buf) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 				assert.Equal(t, tc.expStatus, resp.StatusCode) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 				t.Cleanup(func() { | 
					
						
							|  |  |  | 					err := resp.Body.Close() | 
					
						
							|  |  |  | 					require.NoError(t, err) | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 				if tc.expErrReason == "" { | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 				b, err := io.ReadAll(resp.Body) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				dashboardErr := &errorResponseBody{} | 
					
						
							|  |  |  | 				err = json.Unmarshal(b, dashboardErr) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:53 +08:00
										 |  |  | 				assert.Equal(t, tc.expErrReason, dashboardErr.Message) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run("deleting provisioned dashboard should fail", func(t *testing.T) { | 
					
						
							|  |  |  | 			u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/uid/%s", grafanaListedAddr, dashboardUID) | 
					
						
							|  |  |  | 			req, err := http.NewRequest("DELETE", u, nil) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				fmt.Println(err) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			client := &http.Client{} | 
					
						
							|  |  |  | 			resp, err := client.Do(req) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				err := resp.Body.Close() | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			assert.Equal(t, http.StatusBadRequest, resp.StatusCode) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 			b, err := io.ReadAll(resp.Body) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			dashboardErr := &errorResponseBody{} | 
					
						
							|  |  |  | 			err = json.Unmarshal(b, dashboardErr) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 			assert.Equal(t, dashboards.ErrDashboardCannotDeleteProvisionedDashboard.Reason, dashboardErr.Message) | 
					
						
							| 
									
										
										
										
											2021-12-17 23:31:52 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestIntegrationCreate(t *testing.T) { | 
					
						
							|  |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-31 18:02:19 +08:00
										 |  |  | 	testCreate(t, []string{}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestIntegrationCreateK8s(t *testing.T) { | 
					
						
							|  |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCreate(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func testCreate(t *testing.T, featureToggles []string) { | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	// Setup Grafana and its Database
 | 
					
						
							|  |  |  | 	dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ | 
					
						
							| 
									
										
										
										
											2025-03-31 18:02:19 +08:00
										 |  |  | 		DisableAnonymous:     true, | 
					
						
							|  |  |  | 		EnableFeatureToggles: featureToggles, | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) | 
					
						
							|  |  |  | 	store, cfg := env.SQLStore, env.Cfg | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	// Create user
 | 
					
						
							| 
									
										
										
										
											2024-04-04 21:04:47 +08:00
										 |  |  | 	createUser(t, store, cfg, user.CreateUserCommand{ | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 		DefaultOrgRole: string(org.RoleAdmin), | 
					
						
							|  |  |  | 		Password:       "admin", | 
					
						
							|  |  |  | 		Login:          "admin", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("create dashboard should succeed", func(t *testing.T) { | 
					
						
							|  |  |  | 		dashboardDataOne, err := simplejson.NewJson([]byte(`{"title":"just testing"}`)) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		buf1 := &bytes.Buffer{} | 
					
						
							|  |  |  | 		err = json.NewEncoder(buf1).Encode(dashboards.SaveDashboardCommand{ | 
					
						
							|  |  |  | 			Dashboard: dashboardDataOne, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr) | 
					
						
							|  |  |  | 		// nolint:gosec
 | 
					
						
							|  |  |  | 		resp, err := http.Post(u, "application/json", buf1) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, resp.StatusCode) | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			err := resp.Body.Close() | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		b, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		var m util.DynMap | 
					
						
							|  |  |  | 		err = json.Unmarshal(b, &m) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.NotEmpty(t, m["id"]) | 
					
						
							|  |  |  | 		assert.NotEmpty(t, m["uid"]) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("create dashboard under folder should succeed", func(t *testing.T) { | 
					
						
							|  |  |  | 		folder := createFolder(t, grafanaListedAddr, "test folder") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dashboardDataOne, err := simplejson.NewJson([]byte(`{"title":"just testing"}`)) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		buf1 := &bytes.Buffer{} | 
					
						
							|  |  |  | 		err = json.NewEncoder(buf1).Encode(dashboards.SaveDashboardCommand{ | 
					
						
							|  |  |  | 			Dashboard: dashboardDataOne, | 
					
						
							| 
									
										
										
										
											2023-12-07 20:56:04 +08:00
										 |  |  | 			OrgID:     0, | 
					
						
							| 
									
										
										
										
											2023-12-07 20:15:58 +08:00
										 |  |  | 			FolderUID: folder.UID, | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr) | 
					
						
							|  |  |  | 		// nolint:gosec
 | 
					
						
							|  |  |  | 		resp, err := http.Post(u, "application/json", buf1) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.Equal(t, http.StatusOK, resp.StatusCode) | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			err := resp.Body.Close() | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		b, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		var m util.DynMap | 
					
						
							|  |  |  | 		err = json.Unmarshal(b, &m) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.NotEmpty(t, m["id"]) | 
					
						
							|  |  |  | 		assert.NotEmpty(t, m["uid"]) | 
					
						
							| 
									
										
										
										
											2023-12-07 20:15:58 +08:00
										 |  |  | 		assert.Equal(t, folder.UID, m["folderUid"]) | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("create dashboard under folder (using deprecated folder sequential ID) should succeed", func(t *testing.T) { | 
					
						
							|  |  |  | 		folder := createFolder(t, grafanaListedAddr, "test folder 2") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dashboardDataOne, err := simplejson.NewJson([]byte(`{"title":"just testing"}`)) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		buf1 := &bytes.Buffer{} | 
					
						
							|  |  |  | 		err = json.NewEncoder(buf1).Encode(dashboards.SaveDashboardCommand{ | 
					
						
							|  |  |  | 			Dashboard: dashboardDataOne, | 
					
						
							| 
									
										
										
										
											2023-12-07 20:56:04 +08:00
										 |  |  | 			OrgID:     0, | 
					
						
							|  |  |  | 			FolderUID: folder.UID, | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr) | 
					
						
							|  |  |  | 		// nolint:gosec
 | 
					
						
							|  |  |  | 		resp, err := http.Post(u, "application/json", buf1) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.Equal(t, http.StatusOK, resp.StatusCode) | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			err := resp.Body.Close() | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		b, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		var m util.DynMap | 
					
						
							|  |  |  | 		err = json.Unmarshal(b, &m) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.NotEmpty(t, m["id"]) | 
					
						
							|  |  |  | 		assert.NotEmpty(t, m["uid"]) | 
					
						
							| 
									
										
										
										
											2023-12-07 20:15:58 +08:00
										 |  |  | 		assert.Equal(t, folder.UID, m["folderUid"]) | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("create dashboard under unknow folder should fail", func(t *testing.T) { | 
					
						
							|  |  |  | 		folderUID := "unknown" | 
					
						
							|  |  |  | 		// Import dashboard
 | 
					
						
							|  |  |  | 		dashboardDataOne, err := simplejson.NewJson([]byte(`{"title":"just testing"}`)) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		buf1 := &bytes.Buffer{} | 
					
						
							|  |  |  | 		err = json.NewEncoder(buf1).Encode(dashboards.SaveDashboardCommand{ | 
					
						
							|  |  |  | 			Dashboard: dashboardDataOne, | 
					
						
							|  |  |  | 			FolderUID: folderUID, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr) | 
					
						
							|  |  |  | 		// nolint:gosec
 | 
					
						
							|  |  |  | 		resp, err := http.Post(u, "application/json", buf1) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusBadRequest, resp.StatusCode) | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			err := resp.Body.Close() | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		b, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		var m util.DynMap | 
					
						
							|  |  |  | 		err = json.Unmarshal(b, &m) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-11-16 19:11:35 +08:00
										 |  |  | 		assert.Equal(t, dashboards.ErrFolderNotFound.Error(), m["message"]) | 
					
						
							| 
									
										
										
										
											2023-11-01 23:01:54 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func createFolder(t *testing.T, grafanaListedAddr string, title string) *dtos.Folder { | 
					
						
							|  |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf1 := &bytes.Buffer{} | 
					
						
							|  |  |  | 	err := json.NewEncoder(buf1).Encode(folder.CreateFolderCommand{ | 
					
						
							|  |  |  | 		Title: title, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	u := fmt.Sprintf("http://admin:admin@%s/api/folders", grafanaListedAddr) | 
					
						
							|  |  |  | 	// nolint:gosec
 | 
					
						
							|  |  |  | 	resp, err := http.Post(u, "application/json", buf1) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	assert.Equal(t, http.StatusOK, resp.StatusCode) | 
					
						
							|  |  |  | 	t.Cleanup(func() { | 
					
						
							|  |  |  | 		err := resp.Body.Close() | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	b, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	require.Equal(t, http.StatusOK, resp.StatusCode) | 
					
						
							|  |  |  | 	var f *dtos.Folder | 
					
						
							|  |  |  | 	err = json.Unmarshal(b, &f) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return f | 
					
						
							|  |  |  | } |