Fixed the query parameter 'owner'
[nonrtric.git] / enrichment-coordinator-service / src / test / java / org / oransc / enrichment / ApplicationTest.java
1 /*-
2  * ========================LICENSE_START=================================
3  * ONAP : ccsdk oran
4  * ======================================================================
5  * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
6  * ======================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 package org.oransc.enrichment;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.awaitility.Awaitility.await;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26
27 import com.fasterxml.jackson.core.JsonProcessingException;
28 import com.fasterxml.jackson.databind.JsonMappingException;
29 import com.google.gson.Gson;
30 import com.google.gson.GsonBuilder;
31 import com.google.gson.JsonParser;
32
33 import java.io.FileNotFoundException;
34 import java.io.FileOutputStream;
35 import java.io.PrintStream;
36 import java.util.ArrayList;
37 import java.util.Collection;
38
39 import org.json.JSONObject;
40 import org.junit.jupiter.api.AfterEach;
41 import org.junit.jupiter.api.BeforeEach;
42 import org.junit.jupiter.api.Test;
43 import org.junit.jupiter.api.extension.ExtendWith;
44 import org.oransc.enrichment.clients.AsyncRestClient;
45 import org.oransc.enrichment.clients.ProducerJobInfo;
46 import org.oransc.enrichment.configuration.ApplicationConfig;
47 import org.oransc.enrichment.configuration.ImmutableWebClientConfig;
48 import org.oransc.enrichment.configuration.WebClientConfig;
49 import org.oransc.enrichment.controller.ProducerSimulatorController;
50 import org.oransc.enrichment.controllers.consumer.ConsumerConsts;
51 import org.oransc.enrichment.controllers.consumer.ConsumerEiJobInfo;
52 import org.oransc.enrichment.controllers.consumer.ConsumerEiTypeInfo;
53 import org.oransc.enrichment.controllers.producer.ProducerConsts;
54 import org.oransc.enrichment.controllers.producer.ProducerRegistrationInfo;
55 import org.oransc.enrichment.controllers.producer.ProducerRegistrationInfo.ProducerEiTypeRegistrationInfo;
56 import org.oransc.enrichment.controllers.producer.ProducerStatusInfo;
57 import org.oransc.enrichment.exceptions.ServiceException;
58 import org.oransc.enrichment.repository.EiJob;
59 import org.oransc.enrichment.repository.EiJobs;
60 import org.oransc.enrichment.repository.EiProducers;
61 import org.oransc.enrichment.repository.EiType;
62 import org.oransc.enrichment.repository.EiTypes;
63 import org.oransc.enrichment.tasks.ProducerSupervision;
64 import org.springframework.beans.factory.annotation.Autowired;
65 import org.springframework.boot.test.context.SpringBootTest;
66 import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
67 import org.springframework.boot.test.context.TestConfiguration;
68 import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
69 import org.springframework.boot.web.server.LocalServerPort;
70 import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
71 import org.springframework.context.ApplicationContext;
72 import org.springframework.context.annotation.Bean;
73 import org.springframework.http.HttpStatus;
74 import org.springframework.http.MediaType;
75 import org.springframework.http.ResponseEntity;
76 import org.springframework.test.context.TestPropertySource;
77 import org.springframework.test.context.junit.jupiter.SpringExtension;
78 import org.springframework.web.reactive.function.client.WebClientResponseException;
79
80 import reactor.core.publisher.Mono;
81 import reactor.test.StepVerifier;
82
83 @ExtendWith(SpringExtension.class)
84 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
85 @TestPropertySource(
86     properties = { //
87         "server.ssl.key-store=./config/keystore.jks", //
88         "app.webclient.trust-store=./config/truststore.jks"})
89 class ApplicationTest {
90     private final String EI_TYPE_ID = "typeId";
91     private final String EI_PRODUCER_ID = "producerId";
92     private final String EI_JOB_PROPERTY = "\"property1\"";
93
94     @Autowired
95     ApplicationContext context;
96
97     @Autowired
98     EiJobs eiJobs;
99
100     @Autowired
101     EiTypes eiTypes;
102
103     @Autowired
104     EiProducers eiProducers;
105
106     @Autowired
107     ApplicationConfig applicationConfig;
108
109     @Autowired
110     ProducerSimulatorController producerSimulator;
111
112     @Autowired
113     ProducerSupervision producerSupervision;
114
115     private static Gson gson = new GsonBuilder() //
116         .serializeNulls() //
117         .create(); //
118
119     /**
120      * Overrides the BeanFactory.
121      */
122     @TestConfiguration
123     static class TestBeanFactory {
124         @Bean
125         public ServletWebServerFactory servletContainer() {
126             return new TomcatServletWebServerFactory();
127         }
128     }
129
130     @LocalServerPort
131     private int port;
132
133     @BeforeEach
134     void reset() {
135         this.eiJobs.clear();
136         this.eiTypes.clear();
137         this.eiProducers.clear();
138         this.producerSimulator.getTestResults().reset();
139     }
140
141     @AfterEach
142     void check() {
143         assertThat(this.producerSimulator.getTestResults().errorFound).isFalse();
144     }
145
146     @Test
147     void createApiDoc() throws FileNotFoundException {
148         String url = "/v2/api-docs";
149         ResponseEntity<String> resp = restClient().getForEntity(url).block();
150         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
151
152         String indented = (new JSONObject(resp.getBody())).toString(4);
153         try (PrintStream out = new PrintStream(new FileOutputStream("docs/api.json"))) {
154             out.print(indented);
155         }
156     }
157
158     @Test
159     void testGetEiTypes() throws Exception {
160         putEiProducerWithOneType(EI_PRODUCER_ID, "test");
161         String url = ConsumerConsts.API_ROOT + "/eitypes";
162         String rsp = restClient().get(url).block();
163         assertThat(rsp).isEqualTo("[\"test\"]");
164     }
165
166     @Test
167     void testGetEiTypesEmpty() throws Exception {
168         String url = ConsumerConsts.API_ROOT + "/eitypes";
169         String rsp = restClient().get(url).block();
170         assertThat(rsp).isEqualTo("[]");
171     }
172
173     @Test
174     void testGetEiType() throws Exception {
175         putEiProducerWithOneType(EI_PRODUCER_ID, "test");
176         String url = ConsumerConsts.API_ROOT + "/eitypes/test";
177         String rsp = restClient().get(url).block();
178         ConsumerEiTypeInfo info = gson.fromJson(rsp, ConsumerEiTypeInfo.class);
179         assertThat(info.jobParametersSchema).isNotNull();
180     }
181
182     @Test
183     void testGetEiTypeNotFound() throws Exception {
184         String url = ConsumerConsts.API_ROOT + "/eitypes/junk";
185         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find EI type: junk");
186     }
187
188     @Test
189     void testGetEiJobsIds() throws Exception {
190         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
191         putEiJob(EI_TYPE_ID, "jobId");
192         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs";
193         String rsp = restClient().get(url).block();
194         assertThat(rsp).isEqualTo("[\"jobId\"]");
195
196         url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs?owner=owner";
197         rsp = restClient().get(url).block();
198         assertThat(rsp).isEqualTo("[\"jobId\"]");
199
200         url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs?owner=JUNK";
201         rsp = restClient().get(url).block();
202         assertThat(rsp).isEqualTo("[]");
203     }
204
205     @Test
206     void testGetEiJobTypeNotFound() throws Exception {
207         String url = ConsumerConsts.API_ROOT + "/eitypes/junk/eijobs";
208         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find EI type: junk");
209     }
210
211     @Test
212     void testGetEiJob() throws Exception {
213         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
214         putEiJob(EI_TYPE_ID, "jobId");
215         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId";
216         String rsp = restClient().get(url).block();
217         ConsumerEiJobInfo info = gson.fromJson(rsp, ConsumerEiJobInfo.class);
218         assertThat(info.owner).isEqualTo("owner");
219     }
220
221     @Test
222     void testGetEiJobNotFound() throws Exception {
223         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
224         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/junk";
225         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find EI job: junk");
226     }
227
228     @Test
229     void testGetEiJobStatus() throws Exception {
230         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
231         putEiJob(EI_TYPE_ID, "jobId");
232         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId/status";
233         String rsp = restClient().get(url).block();
234         assertThat(rsp).contains("ENABLED");
235     }
236
237     // Status TBD
238
239     @Test
240     void testDeleteEiJob() throws Exception {
241         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
242         putEiJob(EI_TYPE_ID, "jobId");
243         assertThat(this.eiJobs.size()).isEqualTo(1);
244         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId";
245         restClient().delete(url).block();
246         assertThat(this.eiJobs.size()).isZero();
247
248         ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
249         await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped.size()).isEqualTo(1));
250         assertThat(simulatorResults.jobsStopped.get(0).id).isEqualTo("jobId");
251     }
252
253     @Test
254     void testDeleteEiJobNotFound() throws Exception {
255         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
256         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/junk";
257         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find EI job: junk");
258     }
259
260     @Test
261     void testPutEiJob() throws Exception {
262         // Test that one producer accepting a job is enough
263         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
264         putEiProducerWithOneTypeRejecting("simulateProducerError", EI_TYPE_ID);
265
266         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId";
267         String body = gson.toJson(eiJobInfo());
268         ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
269         assertThat(this.eiJobs.size()).isEqualTo(1);
270         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
271
272         ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
273         await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
274         ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
275         assertThat(request.id).isEqualTo("jobId");
276
277         assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(1);
278
279         resp = restClient().putForEntity(url, body).block();
280         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
281         EiJob job = this.eiJobs.getJob("jobId");
282         assertThat(job.owner()).isEqualTo("owner");
283     }
284
285     @Test
286     void putEiProducerWithOneType_rejecting() throws JsonMappingException, JsonProcessingException, ServiceException {
287         putEiProducerWithOneTypeRejecting("simulateProducerError", EI_TYPE_ID);
288         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId";
289         String body = gson.toJson(eiJobInfo());
290         testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Job not accepted by any producers");
291
292         ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
293         assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(1);
294     }
295
296     @Test
297     void testPutEiJob_jsonSchemavalidationError() throws Exception {
298         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
299
300         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId";
301         // The element with name "property1" is mandatory in the schema
302         ConsumerEiJobInfo jobInfo =
303             new ConsumerEiJobInfo(jsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri");
304         String body = gson.toJson(jobInfo);
305
306         testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Json validation failure");
307     }
308
309     @Test
310     void testGetEiProducerTypes() throws Exception {
311         final String EI_TYPE_ID_2 = EI_TYPE_ID + "_2";
312         putEiProducerWithOneType("producer1", EI_TYPE_ID);
313         putEiJob(EI_TYPE_ID, "jobId");
314         putEiProducerWithOneType("producer2", EI_TYPE_ID_2);
315         putEiJob(EI_TYPE_ID_2, "jobId2");
316         String url = ProducerConsts.API_ROOT + "/eitypes";
317
318         ResponseEntity<String> resp = restClient().getForEntity(url).block();
319         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
320         assertThat(resp.getBody()).contains(EI_TYPE_ID);
321         assertThat(resp.getBody()).contains(EI_TYPE_ID_2);
322     }
323
324     @Test
325     void testReplacingEiProducerTypes() throws Exception {
326         final String REPLACED_TYPE_ID = "replaced";
327         putEiProducerWithOneType(EI_PRODUCER_ID, REPLACED_TYPE_ID);
328         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
329
330         String url = ProducerConsts.API_ROOT + "/eitypes";
331
332         ResponseEntity<String> resp = restClient().getForEntity(url).block();
333         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
334         assertThat(resp.getBody()).contains(EI_TYPE_ID);
335         assertThat(resp.getBody()).doesNotContain(REPLACED_TYPE_ID);
336     }
337
338     @Test
339     void testChangingEiTypeGetRejected() throws Exception {
340         putEiProducerWithOneType("producer1", "typeId1");
341         putEiProducerWithOneType("producer2", "typeId2");
342         putEiJob("typeId1", "jobId");
343
344         String url = ConsumerConsts.API_ROOT + "/eitypes/typeId2/eijobs/jobId";
345         String body = gson.toJson(eiJobInfo());
346         testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT,
347             "Not allowed to change type for existing EI job");
348     }
349
350     @Test
351     void testPutEiProducer() throws Exception {
352         String url = ProducerConsts.API_ROOT + "/eiproducers/eiProducerId";
353         String body = gson.toJson(producerEiRegistratioInfo(EI_TYPE_ID));
354
355         ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
356         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
357
358         assertThat(this.eiTypes.size()).isEqualTo(1);
359         EiType type = this.eiTypes.getType(EI_TYPE_ID);
360         assertThat(type.getProducerIds()).contains("eiProducerId");
361         assertThat(this.eiProducers.size()).isEqualTo(1);
362         assertThat(this.eiProducers.get("eiProducerId").getEiTypes().iterator().next().getId()).isEqualTo(EI_TYPE_ID);
363
364         resp = restClient().putForEntity(url, body).block();
365         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
366
367         resp = restClient().getForEntity(url).block();
368         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
369         assertThat(resp.getBody()).isEqualTo(body);
370     }
371
372     @Test
373     void testPutEiProducerExistingJob() throws Exception {
374         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
375         putEiJob(EI_TYPE_ID, "jobId");
376         String url = ProducerConsts.API_ROOT + "/eiproducers/eiProducerId";
377         String body = gson.toJson(producerEiRegistratioInfo(EI_TYPE_ID));
378         restClient().putForEntity(url, body).block();
379
380         ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
381         await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(2));
382         ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
383         assertThat(request.id).isEqualTo("jobId");
384     }
385
386     @Test
387     void testPutProducerAndEiJob() throws Exception {
388         String url = ProducerConsts.API_ROOT + "/eiproducers/eiProducerId";
389         String body = gson.toJson(producerEiRegistratioInfo(EI_TYPE_ID));
390         restClient().putForEntity(url, body).block();
391         assertThat(this.eiTypes.size()).isEqualTo(1);
392         this.eiTypes.getType(EI_TYPE_ID);
393
394         url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId";
395         body = gson.toJson(eiJobInfo());
396         restClient().putForEntity(url, body).block();
397
398         ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
399         await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
400         ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
401         assertThat(request.id).isEqualTo("jobId");
402     }
403
404     @Test
405     void testGetEiJobsForProducer() throws JsonMappingException, JsonProcessingException, ServiceException {
406         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
407         putEiJob(EI_TYPE_ID, "jobId1");
408         putEiJob(EI_TYPE_ID, "jobId2");
409
410         // PUT a consumer
411         String url = ProducerConsts.API_ROOT + "/eiproducers/eiProducerId";
412         String body = gson.toJson(producerEiRegistratioInfo(EI_TYPE_ID));
413         restClient().putForEntity(url, body).block();
414
415         url = ProducerConsts.API_ROOT + "/eiproducers/eiProducerId/eijobs";
416         ResponseEntity<String> resp = restClient().getForEntity(url).block();
417         assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
418
419         ProducerJobInfo[] parsedResp = gson.fromJson(resp.getBody(), ProducerJobInfo[].class);
420         assertThat(parsedResp[0].typeId).isEqualTo(EI_TYPE_ID);
421         assertThat(parsedResp[1].typeId).isEqualTo(EI_TYPE_ID);
422     }
423
424     @Test
425     void testDeleteEiProducer() throws Exception {
426         putEiProducerWithOneType("eiProducerId", EI_TYPE_ID);
427         putEiProducerWithOneType("eiProducerId2", EI_TYPE_ID);
428
429         assertThat(this.eiProducers.size()).isEqualTo(2);
430         EiType type = this.eiTypes.getType(EI_TYPE_ID);
431         assertThat(type.getProducerIds()).contains("eiProducerId");
432         assertThat(type.getProducerIds()).contains("eiProducerId2");
433         putEiJob(EI_TYPE_ID, "jobId");
434         assertThat(this.eiJobs.size()).isEqualTo(1);
435
436         String url = ProducerConsts.API_ROOT + "/eiproducers/eiProducerId";
437         restClient().deleteForEntity(url).block();
438         assertThat(this.eiProducers.size()).isEqualTo(1);
439         assertThat(this.eiTypes.getType(EI_TYPE_ID).getProducerIds()).doesNotContain("eiProducerId");
440         assertThat(this.eiJobs.size()).isEqualTo(1);
441
442         String url2 = ProducerConsts.API_ROOT + "/eiproducers/eiProducerId2";
443         restClient().deleteForEntity(url2).block();
444         assertThat(this.eiProducers.size()).isZero();
445         assertThat(this.eiTypes.size()).isZero();
446         assertThat(this.eiJobs.size()).isZero();
447     }
448
449     @Test
450     void testGetProducerEiType() throws JsonMappingException, JsonProcessingException, ServiceException {
451         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
452         String url = ProducerConsts.API_ROOT + "/eitypes/" + EI_TYPE_ID;
453         ResponseEntity<String> resp = restClient().getForEntity(url).block();
454         assertThat(resp.getBody()).contains(EI_PRODUCER_ID);
455     }
456
457     @Test
458     void testGetProducerIdentifiers() throws JsonMappingException, JsonProcessingException, ServiceException {
459         putEiProducerWithOneType(EI_PRODUCER_ID, EI_TYPE_ID);
460         String url = ProducerConsts.API_ROOT + "/eiproducers";
461         ResponseEntity<String> resp = restClient().getForEntity(url).block();
462         assertThat(resp.getBody()).contains(EI_PRODUCER_ID);
463     }
464
465     private void assertProducerOpState(String producerId,
466         ProducerStatusInfo.OperationalState expectedOperationalState) {
467         String statusUrl = ProducerConsts.API_ROOT + "/eiproducers/" + producerId + "/status";
468         ResponseEntity<String> resp = restClient().getForEntity(statusUrl).block();
469         ProducerStatusInfo statusInfo = gson.fromJson(resp.getBody(), ProducerStatusInfo.class);
470         assertThat(statusInfo.opState).isEqualTo(expectedOperationalState);
471     }
472
473     @Test
474     void testProducerSupervision() throws JsonMappingException, JsonProcessingException, ServiceException {
475         putEiProducerWithOneTypeRejecting("simulateProducerError", EI_TYPE_ID);
476
477         assertThat(this.eiProducers.size()).isEqualTo(1);
478         assertThat(this.eiTypes.size()).isEqualTo(1);
479         assertProducerOpState("simulateProducerError", ProducerStatusInfo.OperationalState.ENABLED);
480
481         this.producerSupervision.createTask().blockLast();
482         this.producerSupervision.createTask().blockLast();
483         assertThat(this.eiProducers.size()).isEqualTo(1);
484         assertProducerOpState("simulateProducerError", ProducerStatusInfo.OperationalState.DISABLED);
485
486         // After 3 failed checks, the producer shall be deregisterred
487         this.producerSupervision.createTask().blockLast();
488         assertThat(this.eiProducers.size()).isEqualTo(0);
489         assertThat(this.eiTypes.size()).isEqualTo(0);
490     }
491
492     @Test
493     void testGetStatus() throws JsonMappingException, JsonProcessingException, ServiceException {
494         putEiProducerWithOneTypeRejecting("simulateProducerError", EI_TYPE_ID);
495         putEiProducerWithOneTypeRejecting("simulateProducerError2", EI_TYPE_ID);
496
497         String url = "/status";
498         ResponseEntity<String> resp = restClient().getForEntity(url).block();
499         assertThat(resp.getBody()).contains("hunky dory");
500     }
501
502     ProducerEiTypeRegistrationInfo producerEiTypeRegistrationInfo(String typeId)
503         throws JsonMappingException, JsonProcessingException {
504         return new ProducerEiTypeRegistrationInfo(jsonSchemaObject(), typeId);
505     }
506
507     ProducerRegistrationInfo producerEiRegistratioInfoRejecting(String typeId)
508         throws JsonMappingException, JsonProcessingException {
509         Collection<ProducerEiTypeRegistrationInfo> types = new ArrayList<>();
510         types.add(producerEiTypeRegistrationInfo(typeId));
511         return new ProducerRegistrationInfo(types, //
512             baseUrl() + ProducerSimulatorController.JOB_CREATED_ERROR_URL,
513             baseUrl() + ProducerSimulatorController.JOB_DELETED_ERROR_URL,
514             baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL);
515     }
516
517     ProducerRegistrationInfo producerEiRegistratioInfo(String typeId)
518         throws JsonMappingException, JsonProcessingException {
519         Collection<ProducerEiTypeRegistrationInfo> types = new ArrayList<>();
520         types.add(producerEiTypeRegistrationInfo(typeId));
521         return new ProducerRegistrationInfo(types, //
522             baseUrl() + ProducerSimulatorController.JOB_CREATED_URL,
523             baseUrl() + ProducerSimulatorController.JOB_DELETED_URL,
524             baseUrl() + ProducerSimulatorController.SUPERVISION_URL);
525     }
526
527     ConsumerEiJobInfo eiJobInfo() throws JsonMappingException, JsonProcessingException {
528         return new ConsumerEiJobInfo(jsonObject(), "owner", "targetUri");
529     }
530
531     Object jsonObject(String json) {
532         try {
533             return JsonParser.parseString(json).getAsJsonObject();
534         } catch (Exception e) {
535             throw new NullPointerException(e.toString());
536         }
537     }
538
539     Object jsonSchemaObject() {
540         // a json schema with one mandatory property named "string"
541         String schemaStr = "{" //
542             + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," //
543             + "\"type\": \"object\"," //
544             + "\"properties\": {" //
545             + EI_JOB_PROPERTY + " : {" //
546             + "    \"type\": \"string\"" //
547             + "  }" //
548             + "}," //
549             + "\"required\": [" //
550             + EI_JOB_PROPERTY //
551             + "]" //
552             + "}"; //
553         return jsonObject(schemaStr);
554     }
555
556     Object jsonObject() {
557         return jsonObject("{ " + EI_JOB_PROPERTY + " : \"value\" }");
558     }
559
560     private EiJob putEiJob(String eiTypeId, String jobId)
561         throws JsonMappingException, JsonProcessingException, ServiceException {
562
563         String url = ConsumerConsts.API_ROOT + "/eitypes/" + eiTypeId + "/eijobs/" + jobId;
564         String body = gson.toJson(eiJobInfo());
565         restClient().putForEntity(url, body).block();
566
567         return this.eiJobs.getJob(jobId);
568     }
569
570     private EiType putEiProducerWithOneTypeRejecting(String producerId, String eiTypeId)
571         throws JsonMappingException, JsonProcessingException, ServiceException {
572         String url = ProducerConsts.API_ROOT + "/eiproducers/" + producerId;
573         String body = gson.toJson(producerEiRegistratioInfoRejecting(eiTypeId));
574
575         restClient().putForEntity(url, body).block();
576         return this.eiTypes.getType(eiTypeId);
577     }
578
579     private EiType putEiProducerWithOneType(String producerId, String eiTypeId)
580         throws JsonMappingException, JsonProcessingException, ServiceException {
581         String url = ProducerConsts.API_ROOT + "/eiproducers/" + producerId;
582         String body = gson.toJson(producerEiRegistratioInfo(eiTypeId));
583
584         restClient().putForEntity(url, body).block();
585         return this.eiTypes.getType(eiTypeId);
586     }
587
588     private String baseUrl() {
589         return "https://localhost:" + this.port;
590     }
591
592     private AsyncRestClient restClient(boolean useTrustValidation) {
593         WebClientConfig config = this.applicationConfig.getWebClientConfig();
594         config = ImmutableWebClientConfig.builder() //
595             .keyStoreType(config.keyStoreType()) //
596             .keyStorePassword(config.keyStorePassword()) //
597             .keyStore(config.keyStore()) //
598             .keyPassword(config.keyPassword()) //
599             .isTrustStoreUsed(useTrustValidation) //
600             .trustStore(config.trustStore()) //
601             .trustStorePassword(config.trustStorePassword()) //
602             .build();
603
604         return new AsyncRestClient(baseUrl(), config);
605     }
606
607     private AsyncRestClient restClient() {
608         return restClient(false);
609     }
610
611     private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) {
612         testErrorCode(request, expStatus, responseContains, true);
613     }
614
615     private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains,
616         boolean expectApplicationProblemJsonMediaType) {
617         StepVerifier.create(request) //
618             .expectSubscription() //
619             .expectErrorMatches(
620                 t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) //
621             .verify();
622     }
623
624     private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains,
625         boolean expectApplicationProblemJsonMediaType) {
626         assertTrue(throwable instanceof WebClientResponseException);
627         WebClientResponseException responseException = (WebClientResponseException) throwable;
628         assertThat(responseException.getStatusCode()).isEqualTo(expStatus);
629         assertThat(responseException.getResponseBodyAsString()).contains(responseContains);
630         if (expectApplicationProblemJsonMediaType) {
631             assertThat(responseException.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON);
632         }
633         return true;
634     }
635
636 }