Plugins: Replace CDN class with FS CDN type (#113968)
replace cdn class with fs type
This commit is contained in:
@@ -13,7 +13,7 @@ pluginV0Alpha1: {
|
||||
id: string
|
||||
version: string
|
||||
url?: string
|
||||
class: "core" | "external" | "cdn"
|
||||
class: "core" | "external"
|
||||
}
|
||||
}
|
||||
routes: {
|
||||
@@ -233,4 +233,4 @@ pluginV0Alpha1: {
|
||||
title?: string
|
||||
description?: string
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,5 +21,4 @@ type PluginSpecClass string
|
||||
const (
|
||||
PluginSpecClassCore PluginSpecClass = "core"
|
||||
PluginSpecClassExternal PluginSpecClass = "external"
|
||||
PluginSpecClassCdn PluginSpecClass = "cdn"
|
||||
)
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -23,7 +23,6 @@ type Class = string
|
||||
const (
|
||||
ClassCore Class = "core"
|
||||
ClassExternal Class = "external"
|
||||
ClassCDN Class = "cdn"
|
||||
)
|
||||
|
||||
type Source = string
|
||||
|
||||
@@ -446,19 +446,6 @@ func TestPluginInstall_ToPluginInstallV0Alpha1(t *testing.T) {
|
||||
require.Equal(t, pluginsv0alpha1.PluginSpecClass(ClassCore), p.Spec.Class)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cdn class is mapped correctly",
|
||||
install: PluginInstall{
|
||||
ID: "plugin-cdn",
|
||||
Version: "3.0.0",
|
||||
Class: ClassCDN,
|
||||
Source: SourcePluginStore,
|
||||
},
|
||||
namespace: "org-3",
|
||||
validate: func(t *testing.T, p *pluginsv0alpha1.Plugin) {
|
||||
require.Equal(t, pluginsv0alpha1.PluginSpecClass(ClassCDN), p.Spec.Class)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source annotation is set correctly",
|
||||
install: PluginInstall{
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/login/social/socialimpl"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/pluginfakes"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
|
||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||
@@ -265,6 +266,7 @@ func TestIntegrationHTTPServer_GetFrontendSettings_apps(t *testing.T) {
|
||||
Type: plugins.TypeApp,
|
||||
Preload: true,
|
||||
},
|
||||
FS: &pluginfakes.FakePluginFS{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -302,6 +304,7 @@ func TestIntegrationHTTPServer_GetFrontendSettings_apps(t *testing.T) {
|
||||
Type: plugins.TypeApp,
|
||||
Preload: true,
|
||||
},
|
||||
FS: &pluginfakes.FakePluginFS{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -339,6 +342,7 @@ func TestIntegrationHTTPServer_GetFrontendSettings_apps(t *testing.T) {
|
||||
Preload: true,
|
||||
},
|
||||
Angular: plugins.AngularMeta{Detected: true},
|
||||
FS: &pluginfakes.FakePluginFS{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -404,12 +408,12 @@ func TestIntegrationHTTPServer_GetFrontendSettings_apps(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "app plugin with CDN class",
|
||||
desc: "app plugin with CDN fs",
|
||||
pluginStore: func() pluginstore.Store {
|
||||
return &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{
|
||||
Class: plugins.ClassCDN,
|
||||
Class: plugins.ClassExternal,
|
||||
Module: fmt.Sprintf("/%s/module.js", "test-app"),
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "test-app",
|
||||
@@ -417,6 +421,9 @@ func TestIntegrationHTTPServer_GetFrontendSettings_apps(t *testing.T) {
|
||||
Type: plugins.TypeApp,
|
||||
Preload: true,
|
||||
},
|
||||
FS: &pluginfakes.FakePluginFS{TypeFunc: func() plugins.FSType {
|
||||
return plugins.FSTypeCDN
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -545,6 +552,7 @@ func TestIntegrationHTTPServer_GetFrontendSettings_translations(t *testing.T) {
|
||||
"en-US": "public/plugins/test-app/locales/en-US/test-app.json",
|
||||
"pt-BR": "public/plugins/test-app/locales/pt-BR/test-app.json",
|
||||
},
|
||||
FS: &pluginfakes.FakePluginFS{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -594,6 +602,7 @@ func TestIntegrationHTTPServer_GetFrontendSettings_translations(t *testing.T) {
|
||||
"en-US": "public/plugins/test-app/locales/en-US/test-app.json",
|
||||
"pt-BR": "public/plugins/test-app/locales/pt-BR/test-app.json",
|
||||
},
|
||||
FS: &pluginfakes.FakePluginFS{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -633,6 +642,7 @@ func TestIntegrationHTTPServer_GetFrontendSettings_translations(t *testing.T) {
|
||||
"en-US": "public/plugins/test-app/locales/en-US/test-app.json",
|
||||
"pt-BR": "public/plugins/test-app/locales/pt-BR/test-app.json",
|
||||
},
|
||||
FS: &pluginfakes.FakePluginFS{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
+16
-1
@@ -72,12 +72,27 @@ type UpdateInfo struct {
|
||||
type FS interface {
|
||||
fs.FS
|
||||
|
||||
Type() string
|
||||
Type() FSType
|
||||
Base() string
|
||||
Files() ([]string, error)
|
||||
Rel(string) (string, error)
|
||||
}
|
||||
|
||||
type FSType string
|
||||
|
||||
const (
|
||||
FSTypeCDN FSType = "cdn"
|
||||
FSTypeLocal FSType = "local"
|
||||
)
|
||||
|
||||
func (f FSType) CDN() bool {
|
||||
return f == FSTypeCDN
|
||||
}
|
||||
|
||||
func (f FSType) Local() bool {
|
||||
return f == FSTypeLocal
|
||||
}
|
||||
|
||||
type FSRemover interface {
|
||||
Remove() error
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ func NewLocalFS(basePath string) LocalFS {
|
||||
return LocalFS{basePath: basePath}
|
||||
}
|
||||
|
||||
func (f LocalFS) Type() string {
|
||||
return "local"
|
||||
func (f LocalFS) Type() FSType {
|
||||
return FSTypeLocal
|
||||
}
|
||||
|
||||
// fileIsAllowed takes an absolute path to a file and an os.FileInfo for that file, and it checks if access to that
|
||||
@@ -219,7 +219,7 @@ func NewStaticFS(fs FS) (StaticFS, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f StaticFS) Type() string {
|
||||
func (f StaticFS) Type() FSType {
|
||||
return f.FS.Type()
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ func NewPatternListInspector(detectorsProvider angulardetector.DetectorsProvider
|
||||
|
||||
func (i *PatternsListInspector) Inspect(ctx context.Context, p *plugins.Plugin) (isAngular bool, err error) {
|
||||
// CDN plugins are ignored because they should not be using Angular
|
||||
if p.Class == plugins.ClassCDN {
|
||||
if p.FS.Type().CDN() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angulardetector"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/pluginfakes"
|
||||
)
|
||||
|
||||
type fakeDetector struct {
|
||||
@@ -81,7 +82,11 @@ func TestPatternsListInspector(t *testing.T) {
|
||||
{
|
||||
name: "CDN plugins return false without calling detectors",
|
||||
plugin: &plugins.Plugin{
|
||||
Class: plugins.ClassCDN,
|
||||
FS: &pluginfakes.FakePluginFS{
|
||||
TypeFunc: func() plugins.FSType {
|
||||
return plugins.FSTypeCDN
|
||||
},
|
||||
},
|
||||
},
|
||||
fakeDetectors: []*fakeDetector{
|
||||
{returns: true},
|
||||
|
||||
@@ -18,8 +18,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs"
|
||||
)
|
||||
|
||||
const concurrencyLimit = 32
|
||||
|
||||
type Loader struct {
|
||||
cfg *pluginsCfg.PluginManagementCfg
|
||||
discovery discovery.Discoverer
|
||||
@@ -87,37 +85,13 @@ func (l *Loader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins
|
||||
|
||||
st = time.Now()
|
||||
validatedPlugins := []*plugins.Plugin{}
|
||||
type validateResult struct {
|
||||
bootstrappedPlugin *plugins.Plugin
|
||||
err error
|
||||
}
|
||||
validateResults := make(chan validateResult, len(bootstrappedPlugins))
|
||||
|
||||
var limitSize int
|
||||
if src.PluginClass(ctx) == plugins.ClassCDN {
|
||||
limitSize = min(len(bootstrappedPlugins), concurrencyLimit)
|
||||
} else {
|
||||
limitSize = 1
|
||||
}
|
||||
limit := make(chan struct{}, limitSize)
|
||||
for _, bootstrappedPlugin := range bootstrappedPlugins {
|
||||
limit <- struct{}{}
|
||||
go func(p *plugins.Plugin) {
|
||||
err := l.validation.Validate(ctx, p)
|
||||
validateResults <- validateResult{
|
||||
bootstrappedPlugin: bootstrappedPlugin,
|
||||
err: err,
|
||||
}
|
||||
<-limit
|
||||
}(bootstrappedPlugin)
|
||||
}
|
||||
for i := 0; i < len(bootstrappedPlugins); i++ {
|
||||
r := <-validateResults
|
||||
if r.err != nil {
|
||||
l.recordError(ctx, r.bootstrappedPlugin, r.err)
|
||||
err := l.validation.Validate(ctx, bootstrappedPlugin)
|
||||
if err != nil {
|
||||
l.recordError(ctx, bootstrappedPlugin, err)
|
||||
continue
|
||||
}
|
||||
validatedPlugins = append(validatedPlugins, r.bootstrappedPlugin)
|
||||
validatedPlugins = append(validatedPlugins, bootstrappedPlugin)
|
||||
}
|
||||
l.log.Debug("Validated", "class", src.PluginClass(ctx), "duration", time.Since(st), "total", len(validatedPlugins))
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ func newModuleJSValidator() *ModuleJSValidator {
|
||||
|
||||
func (v *ModuleJSValidator) Validate(_ context.Context, p *plugins.Plugin) error {
|
||||
// CDN plugins are ignored because the module.js is guaranteed to exist
|
||||
if p.Class == plugins.ClassCDN {
|
||||
if p.FS.Type().CDN() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -96,6 +96,11 @@ func newAngularDetector(cfg *config.PluginManagementCfg, angularInspector angula
|
||||
}
|
||||
|
||||
func (a *AngularDetector) Validate(ctx context.Context, p *plugins.Plugin) error {
|
||||
// CDN plugins are ignored because they should not be using Angular
|
||||
if p.FS.Type().CDN() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if p.IsExternalPlugin() {
|
||||
var err error
|
||||
|
||||
|
||||
@@ -433,6 +433,7 @@ func (f *FakeActionSetRegistry) RegisterActionSets(_ context.Context, _ string,
|
||||
type FakePluginFS struct {
|
||||
OpenFunc func(name string) (fs.File, error)
|
||||
RemoveFunc func() error
|
||||
TypeFunc func() plugins.FSType
|
||||
RelFunc func(string) (string, error)
|
||||
|
||||
base string
|
||||
@@ -444,10 +445,6 @@ func NewFakePluginFS(base string) *FakePluginFS {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FakePluginFS) Type() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *FakePluginFS) Open(name string) (fs.File, error) {
|
||||
if f.OpenFunc != nil {
|
||||
return f.OpenFunc(name)
|
||||
@@ -462,6 +459,13 @@ func (f *FakePluginFS) Rel(_ string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (f *FakePluginFS) Type() plugins.FSType {
|
||||
if f.TypeFunc != nil {
|
||||
return f.TypeFunc()
|
||||
}
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *FakePluginFS) Base() string {
|
||||
return f.base
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ func newPathSeparatorOverrideFS(sep string, ufs plugins.FS) (fsPathSeparatorFile
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f fsPathSeparatorFiles) Type() string {
|
||||
func (f fsPathSeparatorFiles) Type() plugins.FSType {
|
||||
return f.FS.Type()
|
||||
}
|
||||
|
||||
|
||||
@@ -42,15 +42,6 @@ func TestLocalProvider_Module(t *testing.T) {
|
||||
},
|
||||
expected: "public/plugins/external-plugin/module.js",
|
||||
},
|
||||
{
|
||||
name: "CDN plugin should use standard path",
|
||||
plugin: PluginInfo{
|
||||
JsonData: plugins.JSONData{ID: "cdn-plugin"},
|
||||
Class: plugins.ClassCDN,
|
||||
FS: plugins.NewLocalFS("/cdn/plugins/cdn-plugin"),
|
||||
},
|
||||
expected: "public/plugins/cdn-plugin/module.js",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -496,7 +496,7 @@ func (p *Plugin) IsCorePlugin() bool {
|
||||
}
|
||||
|
||||
func (p *Plugin) IsExternalPlugin() bool {
|
||||
return !p.IsCorePlugin()
|
||||
return p.Class == ClassExternal
|
||||
}
|
||||
|
||||
type Class string
|
||||
@@ -504,7 +504,6 @@ type Class string
|
||||
const (
|
||||
ClassCore Class = "core"
|
||||
ClassExternal Class = "external"
|
||||
ClassCDN Class = "cdn"
|
||||
)
|
||||
|
||||
func (c Class) String() string {
|
||||
|
||||
@@ -47,7 +47,7 @@ func (f inMemoryFS) Open(fn string) (fs.File, error) {
|
||||
return &inMemoryFile{path: fn, reader: bytes.NewReader(f.files[fn])}, nil
|
||||
}
|
||||
|
||||
func (f inMemoryFS) Type() string {
|
||||
func (f inMemoryFS) Type() FSType {
|
||||
return "in-memory"
|
||||
}
|
||||
|
||||
|
||||
@@ -1076,9 +1076,9 @@ func TestLoader_AngularClass(t *testing.T) {
|
||||
expAngularDetectionRun: true,
|
||||
},
|
||||
{
|
||||
name: "other-class plugin should run angular detection",
|
||||
class: "CDN", // (enterprise-only class)
|
||||
expAngularDetectionRun: true,
|
||||
name: "other class plugin should skip angular detection",
|
||||
class: "foo",
|
||||
expAngularDetectionRun: false,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -1086,7 +1086,7 @@ func TestLoader_AngularClass(t *testing.T) {
|
||||
PluginClassFunc: func(ctx context.Context) plugins.Class {
|
||||
return tc.class
|
||||
},
|
||||
DiscoverFunc: sources.NewLocalSource(plugins.ClassExternal, []string{filepath.Join(testDataDir(t), "valid-v2-signature")}).Discover,
|
||||
DiscoverFunc: sources.NewLocalSource(tc.class, []string{filepath.Join(testDataDir(t), "valid-v2-signature")}).Discover,
|
||||
}
|
||||
// if angularDetected = true, it means that the detection has run
|
||||
l := newLoaderWithOpts(t, &config.PluginManagementCfg{}, loaderDepOpts{
|
||||
|
||||
@@ -149,7 +149,7 @@ func ReportFSMetrics(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, err
|
||||
return p, nil
|
||||
}
|
||||
|
||||
metrics.SetPluginFSInformation(p.ID, p.FS.Type())
|
||||
metrics.SetPluginFSInformation(p.ID, string(p.FS.Type()))
|
||||
return p, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -70,12 +70,12 @@ func (s *Service) LoadingStrategy(_ context.Context, p pluginstore.Plugin) plugi
|
||||
|
||||
// Since the parent plugin is not explicitly configured as script loading compatible,
|
||||
// If the plugin is either loaded from the CDN (via its parent) or contains Angular, we should use fetch
|
||||
if s.cdnEnabled(p.Parent.ID, p.Class) || p.Angular.Detected {
|
||||
if s.cdnEnabled(p.Parent.ID, p.FS) || p.Angular.Detected {
|
||||
return plugins.LoadingStrategyFetch
|
||||
}
|
||||
}
|
||||
|
||||
if !s.cdnEnabled(p.ID, p.Class) && !p.Angular.Detected {
|
||||
if !s.cdnEnabled(p.ID, p.FS) && !p.Angular.Detected {
|
||||
return plugins.LoadingStrategyScript
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ func (s *Service) moduleHash(ctx context.Context, p pluginstore.Plugin, childFSB
|
||||
// CDN plugins have the version as part of the URL, which acts as a cache-buster.
|
||||
// Needed due to: https://github.com/grafana/plugin-tools/pull/1426
|
||||
// FS plugins build before this change will have SRI mismatch issues.
|
||||
if !s.cdnEnabled(p.ID, p.Class) {
|
||||
if !s.cdnEnabled(p.ID, p.FS) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ func (s *Service) compatibleCreatePluginVersion(ps map[string]string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Service) cdnEnabled(pluginID string, class plugins.Class) bool {
|
||||
return s.cdn.PluginSupported(pluginID) || class == plugins.ClassCDN
|
||||
func (s *Service) cdnEnabled(pluginID string, fs plugins.FS) bool {
|
||||
return s.cdn.PluginSupported(pluginID) || fs.Type().CDN()
|
||||
}
|
||||
|
||||
// convertHashForSRI takes a SHA256 hash string and returns it as expected by the browser for SRI checks.
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/pluginfakes"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
|
||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||
@@ -58,7 +59,7 @@ func TestService_Calculate(t *testing.T) {
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: futureVersion,
|
||||
}),
|
||||
plugin: newPlugin(pluginID, withAngular(false)),
|
||||
plugin: newPlugin(pluginID, withAngular(false), withFS(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
{
|
||||
@@ -66,16 +67,16 @@ func TestService_Calculate(t *testing.T) {
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
// NOTE: cdn key is not set
|
||||
}),
|
||||
plugin: newPlugin(pluginID, withAngular(false)),
|
||||
plugin: newPlugin(pluginID, withAngular(false), withFS(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyScript when create-plugin version is not compatible, plugin is not angular, is not configured as CDN enabled and does not have the CDN class",
|
||||
name: "Expected LoadingStrategyScript when create-plugin version is not compatible, plugin is not angular, is not configured as CDN enabled and does not have a CDN fs",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: incompatVersion,
|
||||
// NOTE: cdn key is not set
|
||||
}),
|
||||
plugin: newPlugin(pluginID, withAngular(false), withClass(plugins.ClassExternal)),
|
||||
plugin: newPlugin(pluginID, withAngular(false), withClass(plugins.ClassExternal), withFS(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
{
|
||||
@@ -107,14 +108,14 @@ func TestService_Calculate(t *testing.T) {
|
||||
{
|
||||
name: "Expected LoadingStrategyFetch when parent create-plugin version is not set, is not configured as CDN enabled and plugin is angular",
|
||||
pluginSettings: setting.PluginSettings{},
|
||||
plugin: newPlugin(pluginID, withAngular(true), func(p pluginstore.Plugin) pluginstore.Plugin {
|
||||
plugin: newPlugin(pluginID, withAngular(true), withFS(plugins.NewFakeFS()), func(p pluginstore.Plugin) pluginstore.Plugin {
|
||||
p.Parent = &pluginstore.ParentPlugin{ID: "parent-datasource"}
|
||||
return p
|
||||
}),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyFetch when create-plugin version is not compatible, plugin is not angular, is configured as CDN enabled and does not have the CDN class",
|
||||
name: "Expected LoadingStrategyFetch when create-plugin version is not compatible, plugin is not angular, and plugin is configured as CDN enabled",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
"cdn": "true",
|
||||
CreatePluginVersionCfgKey: incompatVersion,
|
||||
@@ -127,7 +128,7 @@ func TestService_Calculate(t *testing.T) {
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: incompatVersion,
|
||||
}),
|
||||
plugin: newPlugin(pluginID, withAngular(true)),
|
||||
plugin: newPlugin(pluginID, withAngular(true), withFS(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
@@ -140,19 +141,25 @@ func TestService_Calculate(t *testing.T) {
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyFetch when create-plugin version is not compatible, plugin is not angular and has the CDN class",
|
||||
name: "Expected LoadingStrategyFetch when create-plugin version is not compatible, plugin is not angular and has a CDN fs",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: incompatVersion,
|
||||
}),
|
||||
plugin: newPlugin(pluginID, withAngular(false), withClass(plugins.ClassCDN)),
|
||||
plugin: newPlugin(pluginID, withAngular(false), withFS(
|
||||
&pluginfakes.FakePluginFS{
|
||||
TypeFunc: func() plugins.FSType {
|
||||
return plugins.FSTypeCDN
|
||||
},
|
||||
},
|
||||
)),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyScript when plugin setting create-plugin version is badly formatted, plugin is not configured as CDN enabled and does not have the CDN class",
|
||||
name: "Expected LoadingStrategyScript when plugin setting create-plugin version is badly formatted, plugin is not configured as CDN enabled and does not have a CDN fs",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: "invalidSemver",
|
||||
}),
|
||||
plugin: newPlugin(pluginID, withAngular(false)),
|
||||
plugin: newPlugin(pluginID, withAngular(false), withFS(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
}
|
||||
@@ -183,9 +190,9 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
features *config.Features
|
||||
store []pluginstore.Plugin
|
||||
|
||||
// Can be used to configure plugin's class
|
||||
// cdn class = loaded from CDN with no files on disk
|
||||
// external class = files on disk but served from CDN only if cdn=true
|
||||
// Can be used to configure plugin's fs
|
||||
// fs cdn type = loaded from CDN with no files on disk
|
||||
// fs local type = files on disk but served from CDN only if cdn=true
|
||||
plugin pluginstore.Plugin
|
||||
|
||||
// When true, set cdn=true in config
|
||||
@@ -204,7 +211,7 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
pluginID,
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid"))),
|
||||
withClass(plugins.ClassCDN),
|
||||
withClass(plugins.ClassExternal),
|
||||
),
|
||||
cdn: true,
|
||||
features: &config.Features{SriChecksEnabled: true},
|
||||
@@ -236,7 +243,6 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
pluginID,
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid"))),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
cdn: true,
|
||||
features: &config.Features{SriChecksEnabled: false},
|
||||
@@ -261,7 +267,6 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
parentPluginID,
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-nested"))),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
},
|
||||
plugin: newPlugin(
|
||||
@@ -269,7 +274,6 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-nested", "datasource"))),
|
||||
withParent(parentPluginID),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
cdn: true,
|
||||
features: &config.Features{SriChecksEnabled: true},
|
||||
@@ -284,7 +288,6 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
parentPluginID,
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-nested"))),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
},
|
||||
plugin: newPlugin(
|
||||
@@ -292,7 +295,6 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-nested", "panels", "one"))),
|
||||
withParent(parentPluginID),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
cdn: true,
|
||||
features: &config.Features{SriChecksEnabled: true},
|
||||
@@ -308,14 +310,12 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
"grand-parent-app",
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-deeply-nested"))),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
newPlugin(
|
||||
"parent-datasource",
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-deeply-nested", "datasource"))),
|
||||
withParent("grand-parent-app"),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
},
|
||||
plugin: newPlugin(
|
||||
@@ -323,7 +323,6 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-deeply-nested", "datasource", "panels", "one"))),
|
||||
withParent("parent-datasource"),
|
||||
withClass(plugins.ClassCDN),
|
||||
),
|
||||
cdn: true,
|
||||
features: &config.Features{SriChecksEnabled: true},
|
||||
@@ -378,11 +377,17 @@ func TestService_ModuleHash(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var pluginSettings setting.PluginSettings
|
||||
if tc.cdn {
|
||||
pluginSettings = newPluginSettings(pluginID, map[string]string{
|
||||
"cdn": "true",
|
||||
})
|
||||
} else {
|
||||
require.NotEqual(t, plugins.ClassCDN, tc.plugin.Class, "plugin should not have the CDN class because CDN is disabled")
|
||||
pluginSettings = setting.PluginSettings{
|
||||
pluginID: {
|
||||
"cdn": "true",
|
||||
},
|
||||
parentPluginID: map[string]string{
|
||||
"cdn": "true",
|
||||
},
|
||||
"grand-parent-app": map[string]string{
|
||||
"cdn": "true",
|
||||
},
|
||||
}
|
||||
}
|
||||
features := tc.features
|
||||
if features == nil {
|
||||
@@ -439,8 +444,24 @@ func TestService_ModuleHash_Cache(t *testing.T) {
|
||||
withInfo(plugins.Info{Version: "1.0.0"}),
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid"))),
|
||||
withClass(plugins.ClassCDN),
|
||||
)
|
||||
|
||||
pCfg = &config.PluginManagementCfg{
|
||||
PluginsCDNURLTemplate: "https://cdn.grafana.com",
|
||||
PluginSettings: setting.PluginSettings{
|
||||
pluginID: {
|
||||
"cdn": "true",
|
||||
},
|
||||
},
|
||||
Features: config.Features{SriChecksEnabled: true},
|
||||
}
|
||||
svc = ProvideService(
|
||||
pCfg,
|
||||
pluginscdn.ProvideService(pCfg),
|
||||
signature.ProvideService(pCfg, statickey.New()),
|
||||
pluginstore.NewFakePluginStore(),
|
||||
)
|
||||
|
||||
k := svc.moduleHashCacheKey(pV1)
|
||||
|
||||
_, ok := svc.moduleHashCache.Load(k)
|
||||
@@ -461,7 +482,6 @@ func TestService_ModuleHash_Cache(t *testing.T) {
|
||||
withSignatureStatus(plugins.SignatureStatusValid),
|
||||
// different fs for different hash
|
||||
withFS(plugins.NewLocalFS(filepath.Join("testdata", "module-hash-valid-nested"))),
|
||||
withClass(plugins.ClassCDN),
|
||||
)
|
||||
mhV2 := svc.ModuleHash(context.Background(), pV2)
|
||||
require.NotEqual(t, mhV2, mhV1, "different version should have different hash")
|
||||
|
||||
Reference in New Issue
Block a user