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