Fix for feature flag handling (#1753)
* fix for handling feature flags changing * update tests * fix tests * lint fixes * feedback updates * use getConfig instead * linter fix * more linter * revert changes Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
parent
ad0e3a1248
commit
f74eea11ba
4 changed files with 84 additions and 89 deletions
|
@ -2,9 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/mattermost/focalboard/server/utils"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// configuration captures the plugin's external configuration as exposed in the Mattermost server
|
// configuration captures the plugin's external configuration as exposed in the Mattermost server
|
||||||
|
@ -71,21 +68,28 @@ func (p *Plugin) setConfiguration(configuration *configuration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnConfigurationChange is invoked when configuration changes may have been made.
|
// OnConfigurationChange is invoked when configuration changes may have been made.
|
||||||
func (p *Plugin) OnConfigurationChange() error {
|
func (p *Plugin) OnConfigurationChange() error { //nolint
|
||||||
// Have we been setup by OnActivate?
|
// Have we been setup by OnActivate?
|
||||||
if p.wsPluginAdapter == nil {
|
if p.wsPluginAdapter == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration := &configuration{}
|
mmconfig := p.API.GetConfig()
|
||||||
// Load the public configuration fields from the Mattermost server configuration.
|
|
||||||
if err := p.API.LoadPluginConfiguration(&configuration); err != nil {
|
// handle plugin configuration settings
|
||||||
return errors.Wrap(err, "failed to load plugin configuration")
|
enableShareBoards := false
|
||||||
|
if mmconfig.PluginSettings.Plugins[pluginName][sharedBoardsName] == true {
|
||||||
|
enableShareBoards = true
|
||||||
|
}
|
||||||
|
configuration := &configuration{
|
||||||
|
EnablePublicSharedBoards: enableShareBoards,
|
||||||
}
|
}
|
||||||
|
|
||||||
p.setConfiguration(configuration)
|
p.setConfiguration(configuration)
|
||||||
p.server.UpdateClientConfig(utils.StructToMap(configuration))
|
p.server.Config().EnablePublicSharedBoards = enableShareBoards
|
||||||
p.wsPluginAdapter.BroadcastConfigChange(*p.server.App().GetClientConfig())
|
|
||||||
|
|
||||||
|
// handle feature flags
|
||||||
|
p.server.Config().FeatureFlags = parseFeatureFlags(mmconfig.FeatureFlags.ToMap())
|
||||||
|
p.server.UpdateAppConfig()
|
||||||
|
p.wsPluginAdapter.BroadcastConfigChange(*p.server.App().GetClientConfig())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +1,85 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mattermost/focalboard/server/model"
|
"github.com/mattermost/focalboard/server/model"
|
||||||
|
"github.com/mattermost/focalboard/server/server"
|
||||||
|
"github.com/mattermost/focalboard/server/services/config"
|
||||||
"github.com/mattermost/focalboard/server/ws"
|
"github.com/mattermost/focalboard/server/ws"
|
||||||
|
serverModel "github.com/mattermost/mattermost-server/v6/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/plugin/plugintest"
|
"github.com/mattermost/mattermost-server/v6/plugin/plugintest"
|
||||||
"github.com/mattermost/mattermost-server/v6/plugin/plugintest/mock"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var errLoadPluginConfiguration = errors.New("loadPluginConfiguration Error")
|
type TestHelper struct {
|
||||||
|
Server *server.Server
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfiguration(t *testing.T) {
|
func SetupTestHelper() *TestHelper {
|
||||||
t.Run("null configuration", func(t *testing.T) {
|
th := &TestHelper{}
|
||||||
plugin := &Plugin{}
|
th.Server = newTestServer()
|
||||||
assert.NotNil(t, plugin.getConfiguration())
|
return th
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestServer() *server.Server {
|
||||||
|
srv, err := server.New(server.Params{
|
||||||
|
Cfg: &config.Configuration{},
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("changing configuration", func(t *testing.T) {
|
return srv
|
||||||
plugin := &Plugin{}
|
}
|
||||||
|
|
||||||
configuration1 := &configuration{EnablePublicSharedBoards: false}
|
func TestConfigurationNullConfiguration(t *testing.T) {
|
||||||
plugin.setConfiguration(configuration1)
|
plugin := &Plugin{}
|
||||||
assert.Equal(t, configuration1, plugin.getConfiguration())
|
assert.NotNil(t, plugin.getConfiguration())
|
||||||
|
|
||||||
configuration2 := &configuration{EnablePublicSharedBoards: true}
|
|
||||||
plugin.setConfiguration(configuration2)
|
|
||||||
assert.Equal(t, configuration2, plugin.getConfiguration())
|
|
||||||
assert.NotEqual(t, configuration1, plugin.getConfiguration())
|
|
||||||
assert.False(t, plugin.getConfiguration() == configuration1)
|
|
||||||
assert.True(t, plugin.getConfiguration() == configuration2)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("setting same configuration", func(t *testing.T) {
|
|
||||||
plugin := &Plugin{}
|
|
||||||
|
|
||||||
configuration1 := &configuration{}
|
|
||||||
plugin.setConfiguration(configuration1)
|
|
||||||
assert.Panics(t, func() {
|
|
||||||
plugin.setConfiguration(configuration1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("clearing configuration", func(t *testing.T) {
|
|
||||||
plugin := &Plugin{}
|
|
||||||
|
|
||||||
configuration1 := &configuration{EnablePublicSharedBoards: true}
|
|
||||||
plugin.setConfiguration(configuration1)
|
|
||||||
assert.NotPanics(t, func() {
|
|
||||||
plugin.setConfiguration(nil)
|
|
||||||
})
|
|
||||||
assert.NotNil(t, plugin.getConfiguration())
|
|
||||||
assert.NotEqual(t, configuration1, plugin.getConfiguration())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOnConfigurationChange(t *testing.T) {
|
func TestOnConfigurationChange(t *testing.T) {
|
||||||
t.Run("Test LoadPlugin Error", func(t *testing.T) {
|
stringRef := ""
|
||||||
api := &plugintest.API{}
|
|
||||||
api.On("LoadPluginConfiguration",
|
|
||||||
mock.Anything).Return(func(dest interface{}) error {
|
|
||||||
return errLoadPluginConfiguration
|
|
||||||
})
|
|
||||||
|
|
||||||
p := Plugin{}
|
basePlugins := make(map[string]map[string]interface{})
|
||||||
p.SetAPI(api)
|
basePlugins[pluginName] = make(map[string]interface{})
|
||||||
p.wsPluginAdapter = &ws.PluginAdapter{}
|
basePlugins[pluginName][sharedBoardsName] = true
|
||||||
|
|
||||||
err := p.OnConfigurationChange()
|
baseFeatureFlags := &serverModel.FeatureFlags{
|
||||||
assert.Error(t, err)
|
BoardsFeatureFlags: "Feature1-Feature2",
|
||||||
})
|
}
|
||||||
|
basePluginSettings := &serverModel.PluginSettings{
|
||||||
|
Directory: &stringRef,
|
||||||
|
Plugins: basePlugins,
|
||||||
|
}
|
||||||
|
|
||||||
|
baseConfig := &serverModel.Config{
|
||||||
|
FeatureFlags: baseFeatureFlags,
|
||||||
|
PluginSettings: *basePluginSettings,
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("Test Load Plugin Success", func(t *testing.T) {
|
t.Run("Test Load Plugin Success", func(t *testing.T) {
|
||||||
|
th := SetupTestHelper()
|
||||||
api := &plugintest.API{}
|
api := &plugintest.API{}
|
||||||
api.On("LoadPluginConfiguration", mock.AnythingOfType("**main.configuration")).Return(nil)
|
api.On("GetUnsanitizedConfig").Return(baseConfig)
|
||||||
|
|
||||||
p := Plugin{}
|
p := Plugin{}
|
||||||
p.SetAPI(api)
|
p.SetAPI(api)
|
||||||
|
p.server = th.Server
|
||||||
p.wsPluginAdapter = &FakePluginAdapter{}
|
p.wsPluginAdapter = &FakePluginAdapter{}
|
||||||
|
|
||||||
err := p.OnConfigurationChange()
|
err := p.OnConfigurationChange()
|
||||||
require.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, count)
|
assert.Equal(t, 1, count)
|
||||||
|
|
||||||
|
// make sure both App and Server got updated
|
||||||
|
assert.True(t, p.server.Config().EnablePublicSharedBoards)
|
||||||
|
assert.True(t, p.server.App().GetClientConfig().EnablePublicSharedBoards)
|
||||||
|
|
||||||
|
assert.Equal(t, "true", p.server.Config().FeatureFlags["Feature1"])
|
||||||
|
assert.Equal(t, "true", p.server.Config().FeatureFlags["Feature2"])
|
||||||
|
assert.Equal(t, "", p.server.Config().FeatureFlags["Feature3"])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,17 +166,7 @@ func (p *Plugin) createBoardsConfig(mmconfig mmModel.Config, baseURL string, ser
|
||||||
enablePublicSharedBoards = true
|
enablePublicSharedBoards = true
|
||||||
}
|
}
|
||||||
|
|
||||||
featureFlags := make(map[string]string)
|
featureFlags := parseFeatureFlags(mmconfig.FeatureFlags.ToMap())
|
||||||
for key, value := range mmconfig.FeatureFlags.ToMap() {
|
|
||||||
// Break out FeatureFlags and pass remaining
|
|
||||||
if key == boardsFeatureFlagName {
|
|
||||||
for _, flag := range strings.Split(value, "-") {
|
|
||||||
featureFlags[flag] = "true"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
featureFlags[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &config.Configuration{
|
return &config.Configuration{
|
||||||
ServerRoot: baseURL + "/plugins/focalboard",
|
ServerRoot: baseURL + "/plugins/focalboard",
|
||||||
|
@ -204,6 +194,21 @@ func (p *Plugin) createBoardsConfig(mmconfig mmModel.Config, baseURL string, ser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFeatureFlags(configFeatureFlags map[string]string) map[string]string {
|
||||||
|
featureFlags := make(map[string]string)
|
||||||
|
for key, value := range configFeatureFlags {
|
||||||
|
// Break out FeatureFlags and pass remaining
|
||||||
|
if key == boardsFeatureFlagName {
|
||||||
|
for _, flag := range strings.Split(value, "-") {
|
||||||
|
featureFlags[flag] = "true"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
featureFlags[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return featureFlags
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Plugin) OnWebSocketConnect(webConnID, userID string) {
|
func (p *Plugin) OnWebSocketConnect(webConnID, userID string) {
|
||||||
p.wsPluginAdapter.OnWebSocketConnect(webConnID, userID)
|
p.wsPluginAdapter.OnWebSocketConnect(webConnID, userID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,16 +352,7 @@ func (s *Server) App() *app.App {
|
||||||
return s.app
|
return s.app
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) UpdateClientConfig(pluginConfig map[string]interface{}) {
|
func (s *Server) UpdateAppConfig() {
|
||||||
for index, value := range pluginConfig {
|
|
||||||
if index == "EnablePublicSharedBoards" {
|
|
||||||
b, ok := value.(bool)
|
|
||||||
if !ok {
|
|
||||||
s.logger.Warn("Invalid value for config value", mlog.String(index, value.(string)))
|
|
||||||
}
|
|
||||||
s.config.EnablePublicSharedBoards = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.app.SetConfig(s.config)
|
s.app.SetConfig(s.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue