@@ -98,16 +98,54 @@ func TestValidateManifestBundle(t *testing.T) {
9898 manifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" }},{\" apiVersion\" :\" apps/v1\" ,\" kind\" :\" Deployment\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" },\" spec\" :{\" replicas\" :1,\" selector\" :{\" matchLabels\" :{\" app\" :\" nginx\" }},\" template\" :{\" spec\" :{\" containers\" :[{\" name\" :\" nginx\" ,\" image\" :\" quay.io/nginx/nginx-unprivileged:latest\" }]},\" metadata\" :{\" labels\" :{\" app\" :\" nginx\" }}}}}],\" deleteOption\" :{\" propagationPolicy\" :\" Foreground\" },\" manifestConfigs\" :[{\" updateStrategy\" :{\" type\" :\" ServerSideApply\" },\" resourceIdentifier\" :{\" name\" :\" nginx\" ,\" group\" :\" apps\" ,\" resource\" :\" deployments\" ,\" namespace\" :\" default\" }}]}}" ),
9999 },
100100 {
101- name : "invalidated manifest bundle" ,
101+ name : "validated manifest bundle with single manifest" ,
102+ manifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" }}]}}" ),
103+ },
104+ {
105+ name : "validated manifest bundle with empty manifests array" ,
106+ manifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[]}}" ),
107+ },
108+ {
109+ name : "manifest bundle is empty - wrong structure" ,
102110 manifest : newPayload (t , "{\" id\" :\" 75479c10-b537-4261-8058-ca2e36bac384\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" maestro\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" data\" :{\" manifest\" :{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}}}" ),
103- expectedErrorMsg : "manifest is empty" ,
111+ expectedErrorMsg : "manifest bundle is empty" ,
112+ },
113+ {
114+ name : "manifest bundle is nil - no data field" ,
115+ manifest : newPayload (t , "{\" id\" :\" 75479c10-b537-4261-8058-ca2e36bac384\" ,\" time\" :\" 2024-02-05T17:31:05Z\" }" ),
116+ expectedErrorMsg : "failed to decode manifest bundle: failed to convert resource manifest bundle to cloudevent: failed to unmarshal JSONMAP to cloudevent: specversion: no specversion" ,
117+ },
118+ {
119+ name : "failed to decode - empty object" ,
120+ manifest : newPayload (t , "{}" ),
121+ expectedErrorMsg : "manifest bundle is empty" ,
122+ },
123+ {
124+ name : "invalid manifest object - missing apiVersion" ,
125+ manifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" }}]}}" ),
126+ expectedErrorMsg : "apiVersion: Required value: field not set" ,
127+ },
128+ {
129+ name : "invalid manifest object - missing kind" ,
130+ manifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" apiVersion\" :\" v1\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" }}]}}" ),
131+ expectedErrorMsg : "kind: Required value: field not set" ,
132+ },
133+ {
134+ name : "invalid manifest object - missing name" ,
135+ manifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" namespace\" :\" default\" }}]}}" ),
136+ expectedErrorMsg : "metadata.name: Required value: field not set" ,
137+ },
138+ {
139+ name : "invalid manifest object - forbidden field generateName" ,
140+ manifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" generateName\" :\" nginx-\" ,\" namespace\" :\" default\" }}]}}" ),
141+ expectedErrorMsg : "metadata.generateName: Forbidden: field cannot be set" ,
104142 },
105143 }
106144
107145 for _ , c := range cases {
108146 t .Run (c .name , func (t * testing.T ) {
109147 err := ValidateManifestBundle (c .manifest )
110- if err != nil && err .Error () != c .expectedErrorMsg {
148+ if err != nil && strings . TrimSpace ( err .Error () ) != c .expectedErrorMsg {
111149 t .Errorf ("expected %#v but got: %#v" , c .expectedErrorMsg , err )
112150 }
113151 })
@@ -186,84 +224,6 @@ func TestValidateNewObject(t *testing.T) {
186224 }
187225}
188226
189- func TestValidateUpdateManifestBundle (t * testing.T ) {
190- cases := []struct {
191- name string
192- newPayload datatypes.JSONMap
193- oldManifest datatypes.JSONMap
194- expectedErrorMsg string
195- }{
196- {
197- name : "validated manifest" ,
198- newPayload : newPayload (t , "{\" id\" :\" 75479c10-b537-4261-8058-ca2e36bac384\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" }},{\" apiVersion\" :\" apps/v1\" ,\" kind\" :\" Deployment\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" },\" spec\" :{\" replicas\" :1,\" selector\" :{\" matchLabels\" :{\" app\" :\" nginx\" }},\" template\" :{\" spec\" :{\" containers\" :[{\" name\" :\" nginx\" ,\" image\" :\" quay.io/nginx/nginx-unprivileged:latest\" }]},\" metadata\" :{\" labels\" :{\" app\" :\" nginx\" }}}}}],\" deleteOption\" :{\" propagationPolicy\" :\" Foreground\" },\" manifestConfigs\" :[{\" updateStrategy\" :{\" type\" :\" ServerSideApply\" },\" resourceIdentifier\" :{\" name\" :\" nginx\" ,\" group\" :\" apps\" ,\" resource\" :\" deployments\" ,\" namespace\" :\" default\" }}]}}" ),
199- oldManifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" grpc\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" resourceid\" :\" c4df9ff0-bfeb-5bc6-a0ab-4c9128d698b4\" ,\" clustername\" :\" b288a9da-8bfe-4c82-94cc-2b48e773fc46\" ,\" resourceversion\" :1,\" data\" :{\" manifests\" :[{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" }},{\" apiVersion\" :\" apps/v1\" ,\" kind\" :\" Deployment\" ,\" metadata\" :{\" name\" :\" nginx\" ,\" namespace\" :\" default\" },\" spec\" :{\" replicas\" :1,\" selector\" :{\" matchLabels\" :{\" app\" :\" nginx\" }},\" template\" :{\" spec\" :{\" containers\" :[{\" name\" :\" nginx\" ,\" image\" :\" quay.io/nginx/nginx-unprivileged:latest\" }]},\" metadata\" :{\" labels\" :{\" app\" :\" nginx\" }}}}}],\" deleteOption\" :{\" propagationPolicy\" :\" Foreground\" },\" manifestConfigs\" :[{\" updateStrategy\" :{\" type\" :\" ServerSideApply\" },\" resourceIdentifier\" :{\" name\" :\" nginx\" ,\" group\" :\" apps\" ,\" resource\" :\" deployments\" ,\" namespace\" :\" default\" }}]}}" ),
200- },
201- {
202- name : "invalidated manifest" ,
203- newPayload : newPayload (t , "{\" id\" :\" 75479c10-b537-4261-8058-ca2e36bac384\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" maestro\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" data\" :{\" manifest\" :{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}}}" ),
204- oldManifest : newPayload (t , "{\" id\" :\" 266a8cd2-2fab-4e89-9bf0-a56425ebcdf8\" ,\" time\" :\" 2024-02-05T17:31:05Z\" ,\" type\" :\" io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request\" ,\" source\" :\" maestro\" ,\" specversion\" :\" 1.0\" ,\" datacontenttype\" :\" application/json\" ,\" data\" :{\" manifest\" :{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}}}" ),
205- expectedErrorMsg : "new or old manifest is empty" ,
206- },
207- }
208-
209- for _ , c := range cases {
210- t .Run (c .name , func (t * testing.T ) {
211- err := ValidateManifestBundleUpdate (c .newPayload , c .oldManifest )
212- if err != nil && err .Error () != c .expectedErrorMsg {
213- t .Errorf ("expected %#v but got: %#v" , c .expectedErrorMsg , err )
214- }
215- })
216- }
217- }
218-
219- func TestValidateUpdateObject (t * testing.T ) {
220- cases := []struct {
221- name string
222- newPayload datatypes.JSONMap
223- oldManifest datatypes.JSONMap
224- expectedErrorMsg string
225- }{
226- {
227- name : "validated" ,
228- newPayload : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}" ),
229- oldManifest : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}" ),
230- },
231- {
232- name : "apiVersion mismatch" ,
233- newPayload : newPayload (t , "{\" apiVersion\" :\" v2\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}" ),
234- oldManifest : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}" ),
235- expectedErrorMsg : "apiVersion: Invalid value: \" v2\" : field is immutable" ,
236- },
237- {
238- name : "kind mismatch" ,
239- newPayload : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" Test\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}" ),
240- oldManifest : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test\" }}" ),
241- expectedErrorMsg : "kind: Invalid value: \" Test\" : field is immutable" ,
242- },
243- {
244- name : "name mismatch" ,
245- newPayload : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test2\" ,\" namespace\" :\" test\" }}" ),
246- oldManifest : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test1\" ,\" namespace\" :\" test\" }}" ),
247- expectedErrorMsg : "metadata.name: Invalid value: \" test2\" : field is immutable" ,
248- },
249- {
250- name : "namespace mismatch" ,
251- newPayload : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test2\" }}" ),
252- oldManifest : newPayload (t , "{\" apiVersion\" :\" v1\" ,\" kind\" :\" ConfigMap\" ,\" metadata\" :{\" name\" :\" test\" ,\" namespace\" :\" test1\" }}" ),
253- expectedErrorMsg : "metadata.namespace: Invalid value: \" test2\" : field is immutable" ,
254- },
255- }
256-
257- for _ , c := range cases {
258- t .Run (c .name , func (t * testing.T ) {
259- err := ValidateObjectUpdate (c .newPayload , c .oldManifest )
260- if err != nil && err .Error () != c .expectedErrorMsg {
261- t .Errorf ("expected %#v but got: %#v" , c .expectedErrorMsg , err )
262- }
263- })
264- }
265- }
266-
267227func newPayload (t * testing.T , data string ) datatypes.JSONMap {
268228 payload := map [string ]interface {}{}
269229 if err := json .Unmarshal ([]byte (data ), & payload ); err != nil {
0 commit comments