Skip to content

Commit 4039694

Browse files
committed
CONSOLE-4292: e2e test
1 parent 26f7fd4 commit 4039694

File tree

5 files changed

+256
-95
lines changed

5 files changed

+256
-95
lines changed

pkg/console/subresource/configmap/configmap_test.go

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@ import (
88
yaml "gopkg.in/yaml.v2"
99

1010
"github.com/go-test/deep"
11-
"github.com/google/go-cmp/cmp"
1211

1312
corev1 "k8s.io/api/core/v1"
1413
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1514
"k8s.io/utils/ptr"
1615

1716
configv1 "github.com/openshift/api/config/v1"
1817
consolev1 "github.com/openshift/api/console/v1"
19-
v1 "github.com/openshift/api/console/v1"
2018
operatorv1 "github.com/openshift/api/operator/v1"
2119
routev1 "github.com/openshift/api/route/v1"
2220
"github.com/openshift/console-operator/pkg/api"
@@ -61,7 +59,7 @@ func TestDefaultConfigMap(t *testing.T) {
6159
infrastructureConfig *configv1.Infrastructure
6260
rt *routev1.Route
6361
inactivityTimeoutSeconds int
64-
availablePlugins []*v1.ConsolePlugin
62+
availablePlugins []*consolev1.ConsolePlugin
6563
nodeArchitectures []string
6664
nodeOperatingSystems []string
6765
copiedCSVsDisabled bool
@@ -760,7 +758,7 @@ providers: {}
760758
},
761759
},
762760
inactivityTimeoutSeconds: 0,
763-
availablePlugins: []*v1.ConsolePlugin{
761+
availablePlugins: []*consolev1.ConsolePlugin{
764762
testPluginsWithProxy("plugin1", "service1", "service-namespace1"),
765763
testPluginsWithProxy("plugin2", "service2", "service-namespace2"),
766764
testPluginsWithI18nPreloadType("plugin3", "service3", "service-namespace3"),
@@ -1114,15 +1112,15 @@ providers: {}
11141112
}
11151113
}
11161114

1117-
func testPlugins(pluginName, serviceName, serviceNamespace string) *v1.ConsolePlugin {
1118-
return &v1.ConsolePlugin{
1115+
func testPlugins(pluginName, serviceName, serviceNamespace string) *consolev1.ConsolePlugin {
1116+
return &consolev1.ConsolePlugin{
11191117
ObjectMeta: metav1.ObjectMeta{
11201118
Name: pluginName,
11211119
},
1122-
Spec: v1.ConsolePluginSpec{
1123-
Backend: v1.ConsolePluginBackend{
1124-
Type: v1.Service,
1125-
Service: &v1.ConsolePluginService{
1120+
Spec: consolev1.ConsolePluginSpec{
1121+
Backend: consolev1.ConsolePluginBackend{
1122+
Type: consolev1.Service,
1123+
Service: &consolev1.ConsolePluginService{
11261124
Name: serviceName,
11271125
Namespace: serviceNamespace,
11281126
Port: 8443,
@@ -1133,16 +1131,16 @@ func testPlugins(pluginName, serviceName, serviceNamespace string) *v1.ConsolePl
11331131
}
11341132
}
11351133

1136-
func testPluginsWithProxy(pluginName, serviceName, serviceNamespace string) *v1.ConsolePlugin {
1134+
func testPluginsWithProxy(pluginName, serviceName, serviceNamespace string) *consolev1.ConsolePlugin {
11371135
plugin := testPlugins(pluginName, serviceName, serviceNamespace)
1138-
plugin.Spec.Proxy = []v1.ConsolePluginProxy{
1136+
plugin.Spec.Proxy = []consolev1.ConsolePluginProxy{
11391137
{
11401138
Alias: fmt.Sprintf("%s-alias", pluginName),
11411139
CACertificate: validCertificate,
1142-
Authorization: v1.UserToken,
1143-
Endpoint: v1.ConsolePluginProxyEndpoint{
1144-
Type: v1.ProxyTypeService,
1145-
Service: &v1.ConsolePluginProxyServiceConfig{
1140+
Authorization: consolev1.UserToken,
1141+
Endpoint: consolev1.ConsolePluginProxyEndpoint{
1142+
Type: consolev1.ProxyTypeService,
1143+
Service: &consolev1.ConsolePluginProxyServiceConfig{
11461144
Name: fmt.Sprintf("proxy-%s", serviceName),
11471145
Namespace: fmt.Sprintf("proxy-%s", serviceNamespace),
11481146
Port: 9991,
@@ -1154,9 +1152,9 @@ func testPluginsWithProxy(pluginName, serviceName, serviceNamespace string) *v1.
11541152
return plugin
11551153
}
11561154

1157-
func testPluginsWithI18nPreloadType(pluginName, serviceName, serviceNamespace string) *v1.ConsolePlugin {
1155+
func testPluginsWithI18nPreloadType(pluginName, serviceName, serviceNamespace string) *consolev1.ConsolePlugin {
11581156
plugin := testPlugins(pluginName, serviceName, serviceNamespace)
1159-
plugin.Spec.I18n.LoadType = v1.Preload
1157+
plugin.Spec.I18n.LoadType = consolev1.Preload
11601158
return plugin
11611159
}
11621160

@@ -1305,7 +1303,7 @@ func TestAggregateCSPDirectives(t *testing.T) {
13051303
output map[consolev1.DirectiveType][]string
13061304
}{
13071305
{
1308-
name: "Test aggregate CSP directives",
1306+
name: "Test aggregate CSP directives for multiple ConsolePlugins",
13091307
input: []*consolev1.ConsolePlugin{
13101308
{
13111309
Spec: consolev1.ConsolePluginSpec{
@@ -1343,7 +1341,7 @@ func TestAggregateCSPDirectives(t *testing.T) {
13431341
},
13441342
},
13451343
{
1346-
name: "Test aggregate CSP directives",
1344+
name: "Test aggregate CSP directives for a single ConsolePlugin",
13471345
input: []*consolev1.ConsolePlugin{
13481346
{
13491347
Spec: consolev1.ConsolePluginSpec{},
@@ -1373,8 +1371,10 @@ func TestAggregateCSPDirectives(t *testing.T) {
13731371
for _, tt := range tests {
13741372
t.Run(tt.name, func(t *testing.T) {
13751373
result := aggregateCSPDirectives(tt.input)
1376-
if diff := cmp.Diff(tt.output, result); len(diff) > 0 {
1374+
if diff := deep.Equal(tt.output, result); diff != nil {
13771375
t.Error(diff)
1376+
t.Errorf("Got: %v \n", result)
1377+
t.Errorf("Want: %v \n", tt.output)
13781378
}
13791379
})
13801380
}

test/e2e/framework/console-operator.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@ func Pristine(t *testing.T, client *ClientSet) (*operatorsv1.Console, error) {
2525
}
2626
copy := operatorConfig.DeepCopy()
2727
cleanSpec := operatorsv1.ConsoleSpec{}
28-
// we can set a default management state & log level, but
29-
// nothing else should be necessary
28+
// we can set a default
29+
// - ManagementState
30+
// - LogLevel
31+
// - Plugins - since some plugins are enabled by default, eg. networking and monitoring
3032
cleanSpec.ManagementState = operatorsv1.Managed
3133
cleanSpec.LogLevel = operatorsv1.Normal
34+
cleanSpec.Plugins = copy.Spec.Plugins
3235
copy.Spec = cleanSpec
3336
return client.Operator.Consoles().Update(context.TODO(), copy, metav1.UpdateOptions{})
3437
}

test/e2e/plugins_test.go

Lines changed: 135 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,124 +2,187 @@ package e2e
22

33
import (
44
"context"
5+
"fmt"
56
"reflect"
67
"testing"
7-
"time"
88

99
consolev1 "github.com/openshift/api/console/v1"
10-
operatorsv1 "github.com/openshift/api/operator/v1"
10+
consoleapi "github.com/openshift/console-operator/pkg/api"
11+
"github.com/openshift/console-operator/pkg/console/subresource/consoleserver"
12+
"github.com/openshift/console-operator/test/e2e/framework"
13+
"golang.org/x/exp/maps"
1114
yaml "gopkg.in/yaml.v2"
12-
apiErrors "k8s.io/apimachinery/pkg/api/errors"
1315
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14-
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1516
"k8s.io/apimachinery/pkg/util/wait"
1617
"k8s.io/client-go/util/retry"
17-
18-
consoleapi "github.com/openshift/console-operator/pkg/api"
19-
"github.com/openshift/console-operator/pkg/console/subresource/consoleserver"
20-
"github.com/openshift/console-operator/test/e2e/framework"
2118
)
2219

2320
const (
24-
availablePluginName = "test-plugin"
25-
unavailablePluginName = "missing-test-plugin"
26-
pluginServiceEndpoint = "https://test-plugin-service-name.test-plugin-service-namespace.svc.cluster.local:8443/manifest"
27-
expectedPluginNamespace = "plugin__test-plugin"
21+
availablePluginName = "test-plugin"
22+
unavailablePluginName = "missing-test-plugin"
23+
expectedPluginServiceEndpoint = "https://test-plugin-service-name.test-plugin-service-namespace.svc.cluster.local:8443/manifest"
24+
expectedPluginNamespace = "plugin__test-plugin"
25+
)
26+
27+
var (
28+
expectedCSP = map[consolev1.DirectiveType][]string{
29+
consolev1.DefaultSrc: {"source1", "source2", "source3"},
30+
consolev1.StyleSrc: {"style1", "style2"},
31+
consolev1.ImgSrc: {"image1"},
32+
}
33+
34+
pluginCSPs = map[string][]consolev1.ConsolePluginCSP{
35+
fmt.Sprintf("%s-1", availablePluginName): {
36+
{Directive: consolev1.DefaultSrc, Values: []consolev1.CSPDirectiveValue{"source1", "source2"}},
37+
{Directive: consolev1.StyleSrc, Values: []consolev1.CSPDirectiveValue{"style1", "style2"}},
38+
},
39+
fmt.Sprintf("%s-2", availablePluginName): {
40+
{Directive: consolev1.DefaultSrc, Values: []consolev1.CSPDirectiveValue{"source2", "source3"}},
41+
{Directive: consolev1.StyleSrc, Values: []consolev1.CSPDirectiveValue{"style1"}},
42+
{Directive: consolev1.ImgSrc, Values: []consolev1.CSPDirectiveValue{"image1"}},
43+
},
44+
}
2845
)
2946

30-
func setupPluginsTestCase(t *testing.T) (*framework.ClientSet, *operatorsv1.Console) {
31-
return framework.StandardSetup(t)
47+
// setupTestCase initializes test case dependencies and returns a client and list of default plugins.
48+
func setupTestCase(t *testing.T) (*framework.ClientSet, []string) {
49+
client, _ := framework.StandardSetup(t)
50+
defaultPlugins := getOperatorConfigPlugins(t, client)
51+
return client, defaultPlugins
3252
}
3353

34-
func cleanupPluginsTestCase(t *testing.T, client *framework.ClientSet) {
35-
err := client.ConsolePluginV1.Delete(context.TODO(), availablePluginName, metav1.DeleteOptions{})
36-
if err != nil && !apiErrors.IsNotFound(err) {
37-
t.Fatalf("could not delete cleanup %q plugin, %v", availablePluginName, err)
54+
// cleanupTestCase resets any modifications to plugins and cleans up resources.
55+
func cleanupTestCase(t *testing.T, client *framework.ClientSet, defaultPlugins, testPlugins []string) {
56+
for _, plugin := range testPlugins {
57+
deleteConsolePlugin(t, client, plugin)
3858
}
59+
setOperatorConfigPlugins(t, client, defaultPlugins)
3960
framework.StandardCleanup(t, client)
4061
}
4162

42-
// TestAddPlugin is adding available and unavailable plugin names to the console-operator config.
43-
// Only plugin that is available on the cluster will be set with his endpoint into the console-config ConfigMap.
44-
func TestAddV1Plugins(t *testing.T) {
45-
expectedPlugins := map[string]string{availablePluginName: pluginServiceEndpoint}
46-
expertedI18nNamespaces := []string{expectedPluginNamespace}
47-
client, _ := setupPluginsTestCase(t)
48-
defer cleanupPluginsTestCase(t, client)
49-
50-
plugin := &consolev1.ConsolePlugin{
51-
ObjectMeta: v1.ObjectMeta{
52-
Name: availablePluginName,
53-
},
54-
Spec: consolev1.ConsolePluginSpec{
55-
DisplayName: "TestPlugin",
56-
I18n: consolev1.ConsolePluginI18n{
57-
LoadType: consolev1.Preload,
58-
},
59-
Backend: consolev1.ConsolePluginBackend{
60-
Type: consolev1.Service,
61-
Service: &consolev1.ConsolePluginService{
62-
Name: "test-plugin-service-name",
63-
Namespace: "test-plugin-service-namespace",
64-
Port: 8443,
65-
BasePath: "/manifest",
66-
},
67-
},
68-
},
63+
// TestPluginsCSPAggregation verifies correct CSP aggregation from multiple plugins.
64+
func TestPluginsCSPAggregation(t *testing.T) {
65+
client, defaultPlugins := setupTestCase(t)
66+
defer cleanupTestCase(t, client, defaultPlugins, maps.Keys(pluginCSPs))
67+
68+
for name, csp := range pluginCSPs {
69+
createConsolePlugin(t, client, getPlugin(name, csp))
6970
}
71+
setOperatorConfigPlugins(t, client, maps.Keys(pluginCSPs))
72+
verifyConsoleConfigCSP(t, client, expectedCSP)
73+
}
74+
75+
// TestAddPlugins tests addition of available and unavailable plugins.
76+
func TestAddPlugins(t *testing.T) {
77+
expectedPlugins := map[string]string{availablePluginName: expectedPluginServiceEndpoint}
78+
expectedI18nNamespaces := []string{expectedPluginNamespace}
79+
80+
client, defaultPlugins := setupTestCase(t)
81+
defer cleanupTestCase(t, client, defaultPlugins, []string{availablePluginName})
82+
83+
createConsolePlugin(t, client, getPlugin(availablePluginName, nil))
84+
setOperatorConfigPlugins(t, client, []string{availablePluginName, unavailablePluginName})
85+
verifyConsoleConfigPluginsAndNamespaces(t, client, expectedPlugins, expectedI18nNamespaces)
86+
}
7087

71-
_, err := client.ConsolePluginV1.Create(context.TODO(), plugin, metav1.CreateOptions{})
88+
// verifyConsoleConfigCSP checks if the aggregated CSP in the console configuration matches expectations.
89+
func verifyConsoleConfigCSP(t *testing.T, client *framework.ClientSet, expectedCSP map[consolev1.DirectiveType][]string) {
90+
err := wait.Poll(pollFrequency, pollStandardMax, func() (bool, error) {
91+
consoleConfig := getConsoleConfig(t, client)
92+
return reflect.DeepEqual(consoleConfig.ContentSecurityPolicy, expectedCSP), nil
93+
})
7294
if err != nil {
73-
t.Fatalf("could not create v1 ConsolePlugin custom resource: %s", err)
95+
t.Errorf("error verifying aggregated CSP configuration: %v", err)
7496
}
75-
enabledPlugins := []string{availablePluginName, unavailablePluginName}
76-
setOperatorConfigPlugins(t, client, enabledPlugins)
97+
}
7798

78-
err = wait.Poll(1*time.Second, pollTimeout, func() (stop bool, err error) {
99+
// verifyConsoleConfigPluginsAndNamespaces checks if the plugins and namespaces in the console configuration match expectations.
100+
func verifyConsoleConfigPluginsAndNamespaces(t *testing.T, client *framework.ClientSet, expectedPlugins map[string]string, expectedNamespaces []string) {
101+
err := wait.Poll(pollFrequency, pollStandardMax, func() (bool, error) {
79102
consoleConfig := getConsoleConfig(t, client)
80-
if reflect.DeepEqual(expectedPlugins, consoleConfig.Plugins) && reflect.DeepEqual(expertedI18nNamespaces, consoleConfig.I18nNamespaces) {
81-
return true, nil
82-
}
83-
return false, nil
103+
return reflect.DeepEqual(consoleConfig.Plugins, expectedPlugins) &&
104+
reflect.DeepEqual(consoleConfig.I18nNamespaces, expectedNamespaces), nil
84105
})
85106
if err != nil {
86-
t.Errorf("error verifying v1alpha1 ConsolePlugin %q was enabled: %s", availablePluginName, err)
107+
t.Errorf("error verifying ConsolePlugin %q was enabled: %v", availablePluginName, err)
87108
}
88109
}
89110

90-
func setOperatorConfigPlugins(t *testing.T, client *framework.ClientSet, pluginNames []string) {
111+
// setOperatorConfigPlugins updates the console operator's config with enabled plugins.
112+
func setOperatorConfigPlugins(t *testing.T, client *framework.ClientSet, plugins []string) {
91113
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
92114
operatorConfig, err := client.Operator.Consoles().Get(context.TODO(), consoleapi.ConfigResourceName, metav1.GetOptions{})
93115
if err != nil {
94-
t.Fatalf("could not get operator config, %v", err)
95-
}
96-
t.Logf("setting plugins to '%v'", pluginNames)
97-
operatorConfig.Spec = operatorsv1.ConsoleSpec{
98-
OperatorSpec: operatorsv1.OperatorSpec{
99-
ManagementState: "Managed",
100-
},
101-
Plugins: pluginNames,
116+
t.Fatalf("could not get operator config: %v", err)
102117
}
103-
118+
operatorConfig.Spec.Plugins = plugins
104119
_, err = client.Operator.Consoles().Update(context.TODO(), operatorConfig, metav1.UpdateOptions{})
105120
return err
106121
})
107-
108122
if err != nil {
109123
t.Fatalf("could not update operator config plugins: %v", err)
110124
}
111125
}
112126

127+
// getOperatorConfigPlugins retrieves the current plugins from the operator config.
128+
func getOperatorConfigPlugins(t *testing.T, client *framework.ClientSet) []string {
129+
var plugins []string
130+
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
131+
config, err := client.Operator.Consoles().Get(context.TODO(), consoleapi.ConfigResourceName, metav1.GetOptions{})
132+
if err != nil {
133+
t.Fatalf("could not get operator config: %v", err)
134+
}
135+
plugins = config.Spec.Plugins
136+
return nil
137+
})
138+
if err != nil {
139+
t.Fatalf("could not retrieve operator config plugins: %v", err)
140+
}
141+
return plugins
142+
}
143+
144+
// getConsoleConfig unmarshals and returns the console configuration.
113145
func getConsoleConfig(t *testing.T, client *framework.ClientSet) consoleserver.Config {
114146
cm, err := framework.GetConsoleConfigMap(client)
115147
if err != nil {
116-
t.Fatalf("error: %s", err)
148+
t.Fatalf("could not retrieve console config map: %v", err)
117149
}
118-
consoleConfig := consoleserver.Config{}
119-
err = yaml.Unmarshal([]byte(cm.Data["console-config.yaml"]), &consoleConfig)
120-
if err != nil {
121-
t.Fatalf("could not unmarshal console-config.yaml: %v", err)
150+
var consoleConfig consoleserver.Config
151+
if err := yaml.Unmarshal([]byte(cm.Data["console-config.yaml"]), &consoleConfig); err != nil {
152+
t.Fatalf("could not unmarshal console config: %v", err)
122153
}
123-
124154
return consoleConfig
125155
}
156+
157+
// getPlugin constructs a ConsolePlugin resource.
158+
func getPlugin(name string, csp []consolev1.ConsolePluginCSP) *consolev1.ConsolePlugin {
159+
return &consolev1.ConsolePlugin{
160+
ObjectMeta: metav1.ObjectMeta{Name: name},
161+
Spec: consolev1.ConsolePluginSpec{
162+
DisplayName: name,
163+
ContentSecurityPolicy: csp,
164+
I18n: consolev1.ConsolePluginI18n{LoadType: consolev1.Preload},
165+
Backend: consolev1.ConsolePluginBackend{
166+
Type: consolev1.Service,
167+
Service: &consolev1.ConsolePluginService{
168+
Name: "test-plugin-service-name", Namespace: "test-plugin-service-namespace",
169+
Port: 8443, BasePath: "/manifest",
170+
},
171+
},
172+
},
173+
}
174+
}
175+
176+
// createConsolePlugin creates a ConsolePlugin resource in the cluster.
177+
func createConsolePlugin(t *testing.T, client *framework.ClientSet, plugin *consolev1.ConsolePlugin) {
178+
if _, err := client.ConsolePluginV1.Create(context.TODO(), plugin, metav1.CreateOptions{}); err != nil {
179+
t.Fatalf("could not create ConsolePlugin: %v", err)
180+
}
181+
}
182+
183+
// deleteConsolePlugin removes a ConsolePlugin resource from the cluster.
184+
func deleteConsolePlugin(t *testing.T, client *framework.ClientSet, name string) {
185+
if err := client.ConsolePluginV1.Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil {
186+
t.Fatalf("could not delete ConsolePlugin: %v", err)
187+
}
188+
}

0 commit comments

Comments
 (0)