@@ -2,124 +2,187 @@ package e2e
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"reflect"
6
7
"testing"
7
- "time"
8
8
9
9
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"
11
14
yaml "gopkg.in/yaml.v2"
12
- apiErrors "k8s.io/apimachinery/pkg/api/errors"
13
15
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
- v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15
16
"k8s.io/apimachinery/pkg/util/wait"
16
17
"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"
21
18
)
22
19
23
20
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
+ }
28
45
)
29
46
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
32
52
}
33
53
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 )
38
58
}
59
+ setOperatorConfigPlugins (t , client , defaultPlugins )
39
60
framework .StandardCleanup (t , client )
40
61
}
41
62
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 ))
69
70
}
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
+ }
70
87
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
+ })
72
94
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 )
74
96
}
75
- enabledPlugins := []string {availablePluginName , unavailablePluginName }
76
- setOperatorConfigPlugins (t , client , enabledPlugins )
97
+ }
77
98
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 ) {
79
102
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
84
105
})
85
106
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 )
87
108
}
88
109
}
89
110
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 ) {
91
113
err := retry .RetryOnConflict (retry .DefaultBackoff , func () error {
92
114
operatorConfig , err := client .Operator .Consoles ().Get (context .TODO (), consoleapi .ConfigResourceName , metav1.GetOptions {})
93
115
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 )
102
117
}
103
-
118
+ operatorConfig . Spec . Plugins = plugins
104
119
_ , err = client .Operator .Consoles ().Update (context .TODO (), operatorConfig , metav1.UpdateOptions {})
105
120
return err
106
121
})
107
-
108
122
if err != nil {
109
123
t .Fatalf ("could not update operator config plugins: %v" , err )
110
124
}
111
125
}
112
126
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.
113
145
func getConsoleConfig (t * testing.T , client * framework.ClientSet ) consoleserver.Config {
114
146
cm , err := framework .GetConsoleConfigMap (client )
115
147
if err != nil {
116
- t .Fatalf ("error : %s " , err )
148
+ t .Fatalf ("could not retrieve console config map : %v " , err )
117
149
}
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 )
122
153
}
123
-
124
154
return consoleConfig
125
155
}
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