mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			584 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			584 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
| package plugins
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/google/go-cmp/cmp"
 | |
| 	"github.com/grafana/grafana/pkg/services/org"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| )
 | |
| 
 | |
| func Test_ReadPluginJSON(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name       string
 | |
| 		pluginJSON func(t *testing.T) io.ReadCloser
 | |
| 		expected   JSONData
 | |
| 		err        error
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "Valid plugin",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				reader, err := os.Open("manager/testdata/test-app/plugin.json")
 | |
| 				require.NoError(t, err)
 | |
| 				return reader
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:   "test-app",
 | |
| 				Type: TypeApp,
 | |
| 				Name: "Test App",
 | |
| 				Info: Info{
 | |
| 					Author: InfoLink{
 | |
| 						Name: "Test Inc.",
 | |
| 						URL:  "http://test.com",
 | |
| 					},
 | |
| 					Description: "Official Grafana Test App & Dashboard bundle",
 | |
| 					Version:     "1.0.0",
 | |
| 					Links: []InfoLink{
 | |
| 						{Name: "Project site", URL: "http://project.com"},
 | |
| 						{Name: "License & Terms", URL: "http://license.com"},
 | |
| 					},
 | |
| 					Logos: Logos{
 | |
| 						Small: "img/logo_small.png",
 | |
| 						Large: "img/logo_large.png",
 | |
| 					},
 | |
| 					Screenshots: []Screenshots{
 | |
| 						{Path: "img/screenshot1.png", Name: "img1"},
 | |
| 						{Path: "img/screenshot2.png", Name: "img2"},
 | |
| 					},
 | |
| 					Updated:  "2015-02-10",
 | |
| 					Keywords: []string{"test"},
 | |
| 				},
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:        []AddedLink{},
 | |
| 					AddedComponents:   []AddedComponent{},
 | |
| 					AddedFunctions:    []AddedFunction{},
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "3.x.x",
 | |
| 					Plugins: []Dependency{
 | |
| 						{Type: "datasource", ID: "graphite", Name: "Graphite"},
 | |
| 						{Type: "panel", ID: "graph", Name: "Graph"},
 | |
| 					},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 
 | |
| 				Includes: []*Includes{
 | |
| 					{Name: "Nginx Connections", Path: "dashboards/connections.json", Type: "dashboard", Role: org.RoleViewer, Action: ActionAppAccess},
 | |
| 					{Name: "Nginx Memory", Path: "dashboards/memory.json", Type: "dashboard", Role: org.RoleViewer, Action: ActionAppAccess},
 | |
| 					{Name: "Nginx Panel", Type: "panel", Role: org.RoleViewer, Action: ActionAppAccess},
 | |
| 					{Name: "Nginx Datasource", Type: "datasource", Role: org.RoleViewer, Action: ActionAppAccess},
 | |
| 				},
 | |
| 				Backend: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "Invalid plugin JSON",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				reader, err := os.Open("manager/testdata/invalid-plugin-json/plugin.json")
 | |
| 				require.NoError(t, err)
 | |
| 				return reader
 | |
| 			},
 | |
| 			err: ErrInvalidPluginJSON,
 | |
| 		},
 | |
| 		{
 | |
| 			name: "Default value overrides",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "grafana-piechart-panel",
 | |
| 					"name": "This will be overwritten",
 | |
| 					"type": "panel",
 | |
| 					"includes": [
 | |
| 						{"type": "dashboard", "name": "Pie Charts", "path": "dashboards/demo.json"}
 | |
| 					]
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:   "grafana-piechart-panel",
 | |
| 				Type: TypePanel,
 | |
| 				Name: "Pie Chart (old)",
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:      []AddedLink{},
 | |
| 					AddedComponents: []AddedComponent{},
 | |
| 					AddedFunctions:  []AddedFunction{},
 | |
| 
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 
 | |
| 				Includes: []*Includes{
 | |
| 					{Name: "Pie Charts", Path: "dashboards/demo.json", Type: "dashboard", Role: org.RoleViewer},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "Phlare<>Pyroscope rebranding -- hardcoded alias",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "grafana-pyroscope-datasource",
 | |
| 					"type": "datasource",
 | |
| 					"aliasIDs": ["phlare"]
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:       "grafana-pyroscope-datasource",
 | |
| 				AliasIDs: []string{"phlare"}, // Hardcoded from the parser
 | |
| 				Type:     TypeDataSource,
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:      []AddedLink{},
 | |
| 					AddedComponents: []AddedComponent{},
 | |
| 					AddedFunctions:  []AddedFunction{},
 | |
| 
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaDependency: "",
 | |
| 					GrafanaVersion:    "*",
 | |
| 					Plugins:           []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "can read the latest versions of extensions information (v2)",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-extensions-app",
 | |
| 					"name": "Extensions App",
 | |
| 					"type": "app",
 | |
| 					"extensions": {
 | |
| 						"addedLinks": [
 | |
| 							{
 | |
| 								"title": "Added link 1",
 | |
| 								"description": "Added link 1 description",
 | |
| 								"targets": ["grafana/dashboard/panel/menu"]
 | |
| 							}
 | |
| 						],
 | |
| 						"addedComponents": [
 | |
| 							{
 | |
| 								"title": "Added component 1",
 | |
| 								"description": "Added component 1 description",
 | |
| 								"targets": ["grafana/user/profile/tab"]
 | |
| 							}
 | |
| 						],
 | |
| 						"exposedComponents": [
 | |
| 							{
 | |
| 								"title": "Exposed component 1",
 | |
| 								"description": "Exposed component 1 description",
 | |
| 								"id": "myorg-extensions-app/component-1/v1"
 | |
| 							}
 | |
| 						],
 | |
| 						"addedFunctions": [
 | |
|               {"targets": ["foo/bar"], "title":"some hook"}
 | |
|             ],
 | |
| 						"extensionPoints": [
 | |
| 							{
 | |
| 								"title": "Extension point 1",
 | |
| 								"description": "Extension points 1 description",
 | |
| 								"id": "myorg-extensions-app/extensions-point-1/v1"
 | |
| 							}
 | |
| 						]
 | |
| 					}
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:   "myorg-extensions-app",
 | |
| 				Name: "Extensions App",
 | |
| 				Type: TypeApp,
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks: []AddedLink{
 | |
| 						{Title: "Added link 1", Description: "Added link 1 description", Targets: []string{"grafana/dashboard/panel/menu"}},
 | |
| 					},
 | |
| 					AddedComponents: []AddedComponent{
 | |
| 
 | |
| 						{Title: "Added component 1", Description: "Added component 1 description", Targets: []string{"grafana/user/profile/tab"}},
 | |
| 					},
 | |
| 					ExposedComponents: []ExposedComponent{
 | |
| 						{Id: "myorg-extensions-app/component-1/v1", Title: "Exposed component 1", Description: "Exposed component 1 description"},
 | |
| 					},
 | |
| 					ExtensionPoints: []ExtensionPoint{
 | |
| 						{Id: "myorg-extensions-app/extensions-point-1/v1", Title: "Extension point 1", Description: "Extension points 1 description"},
 | |
| 					},
 | |
| 					AddedFunctions: []AddedFunction{
 | |
| 						{Targets: []string{"foo/bar"}, Title: "some hook"},
 | |
| 					},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "can read deprecated extensions info (v1) and parse it as v2",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-extensions-app",
 | |
| 					"name": "Extensions App",
 | |
| 					"type": "app",
 | |
| 					"extensions": [
 | |
| 						{
 | |
| 							"extensionPointId": "grafana/dashboard/panel/menu",
 | |
| 							"title": "Added link 1",
 | |
| 							"description": "Added link 1 description",
 | |
| 							"type": "link"
 | |
| 						},
 | |
| 						{
 | |
| 							"extensionPointId": "grafana/dashboard/panel/menu",
 | |
| 							"title": "Added link 2",
 | |
| 							"description": "Added link 2 description",
 | |
| 							"type": "link"
 | |
| 						},
 | |
| 						{
 | |
| 							"extensionPointId": "grafana/user/profile/tab",
 | |
| 							"title": "Added component 1",
 | |
| 							"description": "Added component 1 description",
 | |
| 							"type": "component"
 | |
| 						}
 | |
| 					]
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:   "myorg-extensions-app",
 | |
| 				Name: "Extensions App",
 | |
| 				Type: TypeApp,
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks: []AddedLink{
 | |
| 						{Title: "Added link 1", Description: "Added link 1 description", Targets: []string{"grafana/dashboard/panel/menu"}},
 | |
| 						{Title: "Added link 2", Description: "Added link 2 description", Targets: []string{"grafana/dashboard/panel/menu"}},
 | |
| 					},
 | |
| 					AddedComponents: []AddedComponent{
 | |
| 						{Title: "Added component 1", Description: "Added component 1 description", Targets: []string{"grafana/user/profile/tab"}},
 | |
| 					},
 | |
| 					AddedFunctions:    []AddedFunction{},
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "works if extensions info is empty",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-extensions-app",
 | |
| 					"name": "Extensions App",
 | |
| 					"type": "app",
 | |
| 					"extensions": []
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:   "myorg-extensions-app",
 | |
| 				Name: "Extensions App",
 | |
| 				Type: TypeApp,
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:      []AddedLink{},
 | |
| 					AddedComponents: []AddedComponent{},
 | |
| 					AddedFunctions:  []AddedFunction{},
 | |
| 
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "works if extensions info is completely missing",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-extensions-app",
 | |
| 					"name": "Extensions App",
 | |
| 					"type": "app"
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:   "myorg-extensions-app",
 | |
| 				Name: "Extensions App",
 | |
| 				Type: TypeApp,
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:      []AddedLink{},
 | |
| 					AddedComponents: []AddedComponent{},
 | |
| 					AddedFunctions:  []AddedFunction{},
 | |
| 
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "can read extensions related dependencies",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-extensions-app",
 | |
| 					"name": "Extensions App",
 | |
| 					"type": "app",
 | |
| 					"dependencies": {
 | |
| 						"grafanaDependency": "10.0.0",
 | |
| 						"extensions": {
 | |
| 							"exposedComponents": ["myorg-extensions-app/component-1/v1"]
 | |
| 						}
 | |
| 					}
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:   "myorg-extensions-app",
 | |
| 				Name: "Extensions App",
 | |
| 				Type: TypeApp,
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:        []AddedLink{},
 | |
| 					AddedComponents:   []AddedComponent{},
 | |
| 					AddedFunctions:    []AddedFunction{},
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion:    "*",
 | |
| 					GrafanaDependency: "10.0.0",
 | |
| 					Plugins:           []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{"myorg-extensions-app/component-1/v1"},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "can read languages in a datasource plugin",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-languages-datasource",
 | |
| 					"name": "Languages Datasource",
 | |
| 					"type": "datasource",
 | |
| 					"languages": ["en-US", "pt-BR"]
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:        "myorg-languages-datasource",
 | |
| 				Name:      "Languages Datasource",
 | |
| 				Type:      TypeDataSource,
 | |
| 				Languages: []string{"en-US", "pt-BR"},
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:        []AddedLink{},
 | |
| 					AddedComponents:   []AddedComponent{},
 | |
| 					AddedFunctions:    []AddedFunction{},
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "can read languages in a panel plugin",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-languages-panel",
 | |
| 					"name": "Languages Panel",
 | |
| 					"type": "panel",
 | |
| 					"languages": ["en-US", "pt-BR"]
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:        "myorg-languages-panel",
 | |
| 				Name:      "Languages Panel",
 | |
| 				Type:      TypePanel,
 | |
| 				Languages: []string{"en-US", "pt-BR"},
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:        []AddedLink{},
 | |
| 					AddedComponents:   []AddedComponent{},
 | |
| 					AddedFunctions:    []AddedFunction{},
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "can read languages in an app plugin",
 | |
| 			pluginJSON: func(t *testing.T) io.ReadCloser {
 | |
| 				pJSON := `{
 | |
| 					"id": "myorg-languages-app",
 | |
| 					"name": "Languages App",
 | |
| 					"type": "app",
 | |
| 					"languages": ["en-US", "pt-BR"]
 | |
| 				}`
 | |
| 				return io.NopCloser(strings.NewReader(pJSON))
 | |
| 			},
 | |
| 			expected: JSONData{
 | |
| 				ID:        "myorg-languages-app",
 | |
| 				Name:      "Languages App",
 | |
| 				Type:      TypeApp,
 | |
| 				Languages: []string{"en-US", "pt-BR"},
 | |
| 
 | |
| 				Extensions: Extensions{
 | |
| 					AddedLinks:        []AddedLink{},
 | |
| 					AddedComponents:   []AddedComponent{},
 | |
| 					AddedFunctions:    []AddedFunction{},
 | |
| 					ExposedComponents: []ExposedComponent{},
 | |
| 					ExtensionPoints:   []ExtensionPoint{},
 | |
| 				},
 | |
| 
 | |
| 				Dependencies: Dependencies{
 | |
| 					GrafanaVersion: "*",
 | |
| 					Plugins:        []Dependency{},
 | |
| 					Extensions: ExtensionsDependencies{
 | |
| 						ExposedComponents: []string{},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			p := tt.pluginJSON(t)
 | |
| 			got, err := ReadPluginJSON(p)
 | |
| 
 | |
| 			// Check if the test returns the same error as expected
 | |
| 			// (unneccary to check further if there is an error at this point)
 | |
| 			if tt.err == nil && err != nil {
 | |
| 				t.Errorf("Error while reading pluginJSON: %+v", err)
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			// Check if the test returns the same error as expected
 | |
| 			if tt.err != nil {
 | |
| 				require.ErrorIs(t, err, tt.err)
 | |
| 			}
 | |
| 
 | |
| 			// Check if the test returns the expected pluginJSONData
 | |
| 			if !cmp.Equal(got, tt.expected) {
 | |
| 				t.Errorf("Unexpected pluginJSONData: %v", cmp.Diff(got, tt.expected))
 | |
| 			}
 | |
| 
 | |
| 			// Should be able to close the reader
 | |
| 			require.NoError(t, p.Close())
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func Test_validatePluginJSON(t *testing.T) {
 | |
| 	type args struct {
 | |
| 		data JSONData
 | |
| 	}
 | |
| 	tests := []struct {
 | |
| 		name string
 | |
| 		args args
 | |
| 		err  error
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "Valid case",
 | |
| 			args: args{
 | |
| 				data: JSONData{
 | |
| 					ID:   "grafana-plugin-id",
 | |
| 					Type: TypeDataSource,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "Invalid plugin ID",
 | |
| 			args: args{
 | |
| 				data: JSONData{
 | |
| 					Type: TypePanel,
 | |
| 				},
 | |
| 			},
 | |
| 			err: ErrInvalidPluginJSON,
 | |
| 		},
 | |
| 		{
 | |
| 			name: "Invalid plugin type",
 | |
| 			args: args{
 | |
| 				data: JSONData{
 | |
| 					ID:   "grafana-plugin-id",
 | |
| 					Type: "test",
 | |
| 				},
 | |
| 			},
 | |
| 			err: ErrInvalidPluginJSON,
 | |
| 		},
 | |
| 	}
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			if err := validatePluginJSON(tt.args.data); !errors.Is(err, tt.err) {
 | |
| 				t.Errorf("validatePluginJSON() = %v, want %v", err, tt.err)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 |