Files
releases/plugins/plugins_test.go
Patrick East 99a6f4da67 plugins: Allow plugins to report status to manager
This defines a new status API on the plugins.Manager for plugins
to be able to update their status.

Signed-off-by: Patrick East <east.patrick@gmail.com>
2020-02-07 09:49:41 -05:00

117 lines
3.9 KiB
Go

// Copyright 2020 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package plugins
import (
"context"
"reflect"
"testing"
"github.com/open-policy-agent/opa/storage/inmem"
)
func TestManagerPluginStatusListener(t *testing.T) {
m, err := New([]byte{}, "test", inmem.New())
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
// Start by registering a single listener and validate that it was registered correctly
var l1Status map[string]*Status
m.RegisterPluginStatusListener("l1", func(status map[string]*Status) {
l1Status = status
})
if len(m.pluginStatusListeners) != 1 || m.pluginStatusListeners["l1"] == nil {
t.Fatalf("Expected a single listener named 'l1' got: %+v", m.pluginStatusListeners)
}
// Register a second one, validate both are there
var l2Status map[string]*Status
m.RegisterPluginStatusListener("l2", func(status map[string]*Status) {
l2Status = status
})
if len(m.pluginStatusListeners) != 2 || m.pluginStatusListeners["l2"] == nil {
t.Fatalf("Expected a two listeners named 'l1' and 'l2' got: %+v", m.pluginStatusListeners)
}
// Ensure starting statuses are empty by default
currentStatus := m.PluginStatus()
if len(currentStatus) != 0 {
t.Fatalf("Expected 0 statuses in current plugin status map, got: %+v", currentStatus)
}
// Push an update to a plugin, ensure current status is reflected and listeners were called
m.UpdatePluginStatus("p1", &Status{State: StateOK})
currentStatus = m.PluginStatus()
if len(currentStatus) != 1 || currentStatus["p1"].State != StateOK {
t.Fatalf("Expected 1 statuses in current plugin status map with state OK, got: %+v", currentStatus)
}
if !reflect.DeepEqual(currentStatus, l1Status) || !reflect.DeepEqual(l1Status, l2Status) {
t.Fatalf("Unexpected status in updates:\n\n\texpecting: %+v\n\n\tgot: l1: %+v l2: %+v\n", currentStatus, l1Status, l2Status)
}
// Unregister the first listener, ensure it is removed
m.UnregisterPluginStatusListener("l1")
if len(m.pluginStatusListeners) != 1 || m.pluginStatusListeners["l2"] == nil {
t.Fatalf("Expected a single listeners named 'l2' got: %+v", m.pluginStatusListeners)
}
// Send another update, ensure the status is ok and the remaining listener is still called
m.UpdatePluginStatus("p2", &Status{State: StateErr})
currentStatus = m.PluginStatus()
if len(currentStatus) != 2 || currentStatus["p1"].State != StateOK || currentStatus["p2"].State != StateErr {
t.Fatalf("Unexpected current plugin status, got: %+v", currentStatus)
}
if !reflect.DeepEqual(currentStatus, l2Status) {
t.Fatalf("Unexpected status in updates:\n\n\texpecting: %+v\n\n\tgot: %+v\n", currentStatus, l2Status)
}
// Unregister the last listener
m.UnregisterPluginStatusListener("l2")
if len(m.pluginStatusListeners) != 0 {
t.Fatalf("Expected zero listeners got: %+v", m.pluginStatusListeners)
}
// Ensure updates can still be sent with no listeners
m.UpdatePluginStatus("p2", &Status{State: StateOK})
currentStatus = m.PluginStatus()
if len(currentStatus) != 2 || currentStatus["p1"].State != StateOK || currentStatus["p2"].State != StateOK {
t.Fatalf("Unexpected current plugin status, got: %+v", currentStatus)
}
}
func TestPluginStatusUpdateOnStartAndStop(t *testing.T) {
m, err := New([]byte{}, "test", inmem.New())
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
m.Register("p1", &testPlugin{m})
err = m.Start(context.Background())
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
m.Stop(context.Background())
}
type testPlugin struct {
m *Manager
}
func (p *testPlugin) Start(ctx context.Context) error {
p.m.UpdatePluginStatus("p1", &Status{State: StateOK})
return nil
}
func (p *testPlugin) Stop(ctx context.Context) {
p.m.UpdatePluginStatus("p1", &Status{State: StateNotReady})
}
func (p *testPlugin) Reconfigure(ctx context.Context, config interface{}) {
p.m.UpdatePluginStatus("p1", &Status{State: StateNotReady})
}