move loading strategy into pkg/plugins
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package pluginassets
|
||||
|
||||
import (
|
||||
"github.com/Masterminds/semver/v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||
)
|
||||
|
||||
const (
|
||||
CreatePluginVersionCfgKey = "create_plugin_version"
|
||||
CreatePluginVersionScriptSupportEnabled = "4.15.0"
|
||||
)
|
||||
|
||||
var (
|
||||
scriptLoadingMinSupportedVersion = semver.MustParse(CreatePluginVersionScriptSupportEnabled)
|
||||
)
|
||||
|
||||
// CalculateLoadingStrategy calculates the loading strategy for a plugin.
|
||||
// If a plugin has plugin setting `create_plugin_version` >= 4.15.0, set loadingStrategy to "script".
|
||||
// If a plugin is not loaded via the CDN and is not Angular, set loadingStrategy to "script".
|
||||
// Otherwise, set loadingStrategy to "fetch".
|
||||
func CalculateLoadingStrategy(p *plugins.Plugin, cfg *config.PluginManagementCfg, cdn *pluginscdn.Service) plugins.LoadingStrategy {
|
||||
if cfg != nil && cfg.PluginSettings != nil {
|
||||
if pCfg, ok := cfg.PluginSettings[p.ID]; ok {
|
||||
if compatibleCreatePluginVersion(pCfg) {
|
||||
return plugins.LoadingStrategyScript
|
||||
}
|
||||
}
|
||||
|
||||
// If the plugin has a parent
|
||||
if p.Parent != nil {
|
||||
// Check the parent's create_plugin_version setting
|
||||
if pCfg, ok := cfg.PluginSettings[p.Parent.ID]; ok {
|
||||
if compatibleCreatePluginVersion(pCfg) {
|
||||
return plugins.LoadingStrategyScript
|
||||
}
|
||||
}
|
||||
|
||||
// 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 cdnEnabled(p.Parent, cdn) || p.Angular.Detected {
|
||||
return plugins.LoadingStrategyFetch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !cdnEnabled(p, cdn) && !p.Angular.Detected {
|
||||
return plugins.LoadingStrategyScript
|
||||
}
|
||||
|
||||
return plugins.LoadingStrategyFetch
|
||||
}
|
||||
|
||||
// compatibleCreatePluginVersion checks if the create_plugin_version setting is >= 4.15.0
|
||||
func compatibleCreatePluginVersion(ps map[string]string) bool {
|
||||
if cpv, ok := ps[CreatePluginVersionCfgKey]; ok {
|
||||
createPluginVer, err := semver.NewVersion(cpv)
|
||||
if err != nil {
|
||||
// Invalid semver, treat as incompatible
|
||||
return false
|
||||
}
|
||||
return !createPluginVer.LessThan(scriptLoadingMinSupportedVersion)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package pluginassets
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||
)
|
||||
|
||||
// cdnFS is a simple mock FS that returns CDN type
|
||||
type cdnFS struct {
|
||||
plugins.FS
|
||||
}
|
||||
|
||||
func (f *cdnFS) Type() plugins.FSType {
|
||||
return plugins.FSTypeCDN
|
||||
}
|
||||
|
||||
func TestCalculateLoadingStrategy(t *testing.T) {
|
||||
const pluginID = "grafana-test-datasource"
|
||||
|
||||
const (
|
||||
incompatVersion = "4.14.0"
|
||||
compatVersion = CreatePluginVersionScriptSupportEnabled
|
||||
futureVersion = "5.0.0"
|
||||
)
|
||||
|
||||
tcs := []struct {
|
||||
name string
|
||||
pluginSettings config.PluginSettings
|
||||
plugin *plugins.Plugin
|
||||
expected plugins.LoadingStrategy
|
||||
}{
|
||||
{
|
||||
name: "Expected LoadingStrategyScript when create-plugin version is compatible and plugin is not angular",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: compatVersion,
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false)),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyScript when parent create-plugin version is compatible and plugin is not angular",
|
||||
pluginSettings: newPluginSettings("parent-datasource", map[string]string{
|
||||
CreatePluginVersionCfgKey: compatVersion,
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), func(p *plugins.Plugin) {
|
||||
p.Parent = &plugins.Plugin{
|
||||
JSONData: plugins.JSONData{ID: "parent-datasource"},
|
||||
FS: plugins.NewFakeFS(),
|
||||
}
|
||||
}),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyScript when create-plugin version is future compatible and plugin is not angular",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: futureVersion,
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), withFSForLoadingStrategy(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyScript when create-plugin version is not provided, plugin is not angular and is not configured as CDN enabled",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), withFSForLoadingStrategy(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 a CDN fs",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: incompatVersion,
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), withClassForLoadingStrategy(plugins.ClassExternal), withFSForLoadingStrategy(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyFetch when parent create-plugin version is not set, is configured as CDN enabled and plugin is not angular",
|
||||
pluginSettings: config.PluginSettings{
|
||||
"parent-datasource": {
|
||||
"cdn": "true",
|
||||
},
|
||||
},
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), func(p *plugins.Plugin) {
|
||||
p.Parent = &plugins.Plugin{
|
||||
JSONData: plugins.JSONData{ID: "parent-datasource"},
|
||||
FS: plugins.NewFakeFS(),
|
||||
}
|
||||
}),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyFetch when parent create-plugin version is not set, is configured as CDN enabled and plugin is angular",
|
||||
pluginSettings: config.PluginSettings{
|
||||
"parent-datasource": {
|
||||
"cdn": "true",
|
||||
},
|
||||
},
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(true), func(p *plugins.Plugin) {
|
||||
p.Parent = &plugins.Plugin{
|
||||
JSONData: plugins.JSONData{ID: "parent-datasource"},
|
||||
FS: plugins.NewFakeFS(),
|
||||
}
|
||||
}),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyFetch when parent create-plugin version is not set, is not configured as CDN enabled and plugin is angular",
|
||||
pluginSettings: config.PluginSettings{},
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(true), withFSForLoadingStrategy(plugins.NewFakeFS()), func(p *plugins.Plugin) {
|
||||
p.Parent = &plugins.Plugin{
|
||||
JSONData: plugins.JSONData{ID: "parent-datasource"},
|
||||
FS: plugins.NewFakeFS(),
|
||||
}
|
||||
}),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
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,
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), withClassForLoadingStrategy(plugins.ClassExternal), withFSForLoadingStrategy(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
name: "Expected LoadingStrategyFetch when create-plugin version is not compatible and plugin is angular",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: incompatVersion,
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(true), withFSForLoadingStrategy(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
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,
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), withFSForLoadingStrategy(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyFetch,
|
||||
},
|
||||
{
|
||||
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: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), withFSForLoadingStrategy(
|
||||
&cdnFS{FS: plugins.NewFakeFS()},
|
||||
)),
|
||||
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 a CDN fs",
|
||||
pluginSettings: newPluginSettings(pluginID, map[string]string{
|
||||
CreatePluginVersionCfgKey: "invalidSemver",
|
||||
}),
|
||||
plugin: newPluginForLoadingStrategy(pluginID, withAngularForLoadingStrategy(false), withFSForLoadingStrategy(plugins.NewFakeFS())),
|
||||
expected: plugins.LoadingStrategyScript,
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cfg := &config.PluginManagementCfg{
|
||||
PluginSettings: tc.pluginSettings,
|
||||
}
|
||||
cdn := pluginscdn.ProvideService(&config.PluginManagementCfg{
|
||||
PluginsCDNURLTemplate: "http://cdn.example.com", // required for cdn.PluginSupported check
|
||||
PluginSettings: tc.pluginSettings,
|
||||
})
|
||||
|
||||
got := CalculateLoadingStrategy(tc.plugin, cfg, cdn)
|
||||
assert.Equal(t, tc.expected, got, "unexpected loading strategy")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newPluginForLoadingStrategy(pluginID string, cbs ...func(*plugins.Plugin)) *plugins.Plugin {
|
||||
p := &plugins.Plugin{
|
||||
JSONData: plugins.JSONData{
|
||||
ID: pluginID,
|
||||
},
|
||||
}
|
||||
for _, cb := range cbs {
|
||||
cb(p)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func withAngularForLoadingStrategy(angular bool) func(*plugins.Plugin) {
|
||||
return func(p *plugins.Plugin) {
|
||||
p.Angular = plugins.AngularMeta{Detected: angular}
|
||||
}
|
||||
}
|
||||
|
||||
func withFSForLoadingStrategy(fs plugins.FS) func(*plugins.Plugin) {
|
||||
return func(p *plugins.Plugin) {
|
||||
p.FS = fs
|
||||
}
|
||||
}
|
||||
|
||||
func withClassForLoadingStrategy(class plugins.Class) func(*plugins.Plugin) {
|
||||
return func(p *plugins.Plugin) {
|
||||
p.Class = class
|
||||
}
|
||||
}
|
||||
|
||||
func newPluginSettings(pluginID string, kv map[string]string) config.PluginSettings {
|
||||
return config.PluginSettings{
|
||||
pluginID: kv,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user