2 * ========================LICENSE_START=================================
5 * Copyright (C) 2020 Nordix Foundation
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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===================================
21 package org.oransc.enrichment;
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;
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;
33 import java.io.FileNotFoundException;
34 import java.io.FileOutputStream;
35 import java.io.PrintStream;
36 import java.lang.invoke.MethodHandles;
37 import java.util.Arrays;
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.configuration.ApplicationConfig;
47 import org.oransc.enrichment.configuration.ImmutableHttpProxyConfig;
48 import org.oransc.enrichment.configuration.ImmutableWebClientConfig;
49 import org.oransc.enrichment.configuration.WebClientConfig;
50 import org.oransc.enrichment.configuration.WebClientConfig.HttpProxyConfig;
51 import org.oransc.enrichment.controller.ConsumerSimulatorController;
52 import org.oransc.enrichment.controller.ProducerSimulatorController;
53 import org.oransc.enrichment.controllers.a1e.A1eConsts;
54 import org.oransc.enrichment.controllers.a1e.A1eEiJobInfo;
55 import org.oransc.enrichment.controllers.a1e.A1eEiJobStatus;
56 import org.oransc.enrichment.controllers.a1e.A1eEiTypeInfo;
57 import org.oransc.enrichment.controllers.r1consumer.ConsumerConsts;
58 import org.oransc.enrichment.controllers.r1consumer.ConsumerInfoTypeInfo;
59 import org.oransc.enrichment.controllers.r1consumer.ConsumerJobInfo;
60 import org.oransc.enrichment.controllers.r1consumer.ConsumerJobStatus;
61 import org.oransc.enrichment.controllers.r1consumer.ConsumerTypeRegistrationInfo;
62 import org.oransc.enrichment.controllers.r1consumer.ConsumerTypeSubscriptionInfo;
63 import org.oransc.enrichment.controllers.r1producer.ProducerCallbacks;
64 import org.oransc.enrichment.controllers.r1producer.ProducerConsts;
65 import org.oransc.enrichment.controllers.r1producer.ProducerInfoTypeInfo;
66 import org.oransc.enrichment.controllers.r1producer.ProducerJobInfo;
67 import org.oransc.enrichment.controllers.r1producer.ProducerRegistrationInfo;
68 import org.oransc.enrichment.controllers.r1producer.ProducerStatusInfo;
69 import org.oransc.enrichment.exceptions.ServiceException;
70 import org.oransc.enrichment.repository.InfoJob;
71 import org.oransc.enrichment.repository.InfoJobs;
72 import org.oransc.enrichment.repository.InfoProducer;
73 import org.oransc.enrichment.repository.InfoProducers;
74 import org.oransc.enrichment.repository.InfoType;
75 import org.oransc.enrichment.repository.InfoTypeSubscriptions;
76 import org.oransc.enrichment.repository.InfoTypes;
77 import org.oransc.enrichment.tasks.ProducerSupervision;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80 import org.springframework.beans.factory.annotation.Autowired;
81 import org.springframework.boot.test.context.SpringBootTest;
82 import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
83 import org.springframework.boot.test.context.TestConfiguration;
84 import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
85 import org.springframework.boot.web.server.LocalServerPort;
86 import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
87 import org.springframework.context.ApplicationContext;
88 import org.springframework.context.annotation.Bean;
89 import org.springframework.http.HttpStatus;
90 import org.springframework.http.MediaType;
91 import org.springframework.http.ResponseEntity;
92 import org.springframework.test.context.TestPropertySource;
93 import org.springframework.test.context.junit.jupiter.SpringExtension;
94 import org.springframework.web.reactive.function.client.WebClientResponseException;
96 import reactor.core.publisher.Mono;
97 import reactor.test.StepVerifier;
99 @ExtendWith(SpringExtension.class)
100 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
103 "server.ssl.key-store=./config/keystore.jks", //
104 "app.webclient.trust-store=./config/truststore.jks", //
105 "app.vardata-directory=./target"})
106 class ApplicationTest {
107 private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
109 private final String TYPE_ID = "typeId";
110 private final String PRODUCER_ID = "producerId";
111 private final String EI_JOB_PROPERTY = "\"property1\"";
112 private final String EI_JOB_ID = "jobId";
115 ApplicationContext context;
124 InfoProducers infoProducers;
127 ApplicationConfig applicationConfig;
130 ProducerSimulatorController producerSimulator;
133 ConsumerSimulatorController consumerSimulator;
136 ProducerSupervision producerSupervision;
139 ProducerCallbacks producerCallbacks;
142 InfoTypeSubscriptions infoTypeSubscriptions;
144 private static Gson gson = new GsonBuilder().create();
147 * Overrides the BeanFactory.
150 static class TestBeanFactory {
152 public ServletWebServerFactory servletContainer() {
153 return new TomcatServletWebServerFactory();
162 this.infoJobs.clear();
163 this.infoTypes.clear();
164 this.infoProducers.clear();
165 this.producerSimulator.getTestResults().reset();
166 this.consumerSimulator.getTestResults().reset();
171 assertThat(this.producerSimulator.getTestResults().errorFound).isFalse();
175 void generateApiDoc() throws FileNotFoundException {
176 String url = "/v3/api-docs";
177 ResponseEntity<String> resp = restClient().getForEntity(url).block();
178 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
180 JSONObject jsonObj = new JSONObject(resp.getBody());
181 assertThat(jsonObj.remove("servers")).isNotNull();
183 String indented = jsonObj.toString(4);
184 try (PrintStream out = new PrintStream(new FileOutputStream("api/ecs-api.json"))) {
190 void a1eGetEiTypes() throws Exception {
191 putInfoProducerWithOneType(PRODUCER_ID, "test");
192 String url = A1eConsts.API_ROOT + "/eitypes";
193 String rsp = restClient().get(url).block();
194 assertThat(rsp).isEqualTo("[\"test\"]");
198 void consumerGetInfoTypes() throws Exception {
199 putInfoProducerWithOneType(PRODUCER_ID, "test");
200 String url = ConsumerConsts.API_ROOT + "/info-types";
201 String rsp = restClient().get(url).block();
202 assertThat(rsp).isEqualTo("[\"test\"]");
206 void a1eGetEiTypesEmpty() throws Exception {
207 String url = A1eConsts.API_ROOT + "/eitypes";
208 String rsp = restClient().get(url).block();
209 assertThat(rsp).isEqualTo("[]");
213 void consumerGetEiTypesEmpty() throws Exception {
214 String url = ConsumerConsts.API_ROOT + "/info-types";
215 String rsp = restClient().get(url).block();
216 assertThat(rsp).isEqualTo("[]");
220 void a1eGetEiType() throws Exception {
221 putInfoProducerWithOneType(PRODUCER_ID, "test");
222 String url = A1eConsts.API_ROOT + "/eitypes/test";
223 String rsp = restClient().get(url).block();
224 A1eEiTypeInfo info = gson.fromJson(rsp, A1eEiTypeInfo.class);
225 assertThat(info).isNotNull();
229 void consumerGetEiType() throws Exception {
230 putInfoProducerWithOneType(PRODUCER_ID, "test");
231 String url = ConsumerConsts.API_ROOT + "/info-types/test";
232 String rsp = restClient().get(url).block();
233 ConsumerInfoTypeInfo info = gson.fromJson(rsp, ConsumerInfoTypeInfo.class);
234 assertThat(info).isNotNull();
235 assertThat(info.jobDataSchema).isNotNull();
236 assertThat(info.state).isEqualTo(ConsumerInfoTypeInfo.ConsumerTypeStatusValues.ENABLED);
237 assertThat(info.noOfProducers).isEqualTo(1);
241 void a1eGetEiTypeNotFound() throws Exception {
242 String url = A1eConsts.API_ROOT + "/eitypes/junk";
243 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Information type not found: junk");
247 void consumerGetEiTypeNotFound() throws Exception {
248 String url = ConsumerConsts.API_ROOT + "/info-types/junk";
249 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Information type not found: junk");
253 void a1eGetEiJobsIds() throws Exception {
254 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
255 putEiJob(TYPE_ID, "jobId");
256 final String JOB_ID_JSON = "[\"jobId\"]";
257 String url = A1eConsts.API_ROOT + "/eijobs?infoTypeId=typeId";
258 String rsp = restClient().get(url).block();
259 assertThat(rsp).isEqualTo(JOB_ID_JSON);
261 url = A1eConsts.API_ROOT + "/eijobs?owner=owner";
262 rsp = restClient().get(url).block();
263 assertThat(rsp).isEqualTo(JOB_ID_JSON);
265 url = A1eConsts.API_ROOT + "/eijobs?owner=JUNK";
266 rsp = restClient().get(url).block();
267 assertThat(rsp).isEqualTo("[]");
269 url = A1eConsts.API_ROOT + "/eijobs";
270 rsp = restClient().get(url).block();
271 assertThat(rsp).isEqualTo(JOB_ID_JSON);
273 url = A1eConsts.API_ROOT + "/eijobs?eiTypeId=typeId&&owner=owner";
274 rsp = restClient().get(url).block();
275 assertThat(rsp).isEqualTo(JOB_ID_JSON);
277 url = A1eConsts.API_ROOT + "/eijobs?eiTypeId=JUNK";
278 rsp = restClient().get(url).block();
279 assertThat(rsp).isEqualTo("[]");
283 void consumerGetInformationJobsIds() throws Exception {
284 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
285 putEiJob(TYPE_ID, "jobId");
286 final String JOB_ID_JSON = "[\"jobId\"]";
287 String url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=typeId";
288 String rsp = restClient().get(url).block();
289 assertThat(rsp).isEqualTo(JOB_ID_JSON);
291 url = ConsumerConsts.API_ROOT + "/info-jobs?owner=owner";
292 rsp = restClient().get(url).block();
293 assertThat(rsp).isEqualTo(JOB_ID_JSON);
295 url = ConsumerConsts.API_ROOT + "/info-jobs?owner=JUNK";
296 rsp = restClient().get(url).block();
297 assertThat(rsp).isEqualTo("[]");
299 url = ConsumerConsts.API_ROOT + "/info-jobs";
300 rsp = restClient().get(url).block();
301 assertThat(rsp).isEqualTo(JOB_ID_JSON);
303 url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=typeId&&owner=owner";
304 rsp = restClient().get(url).block();
305 assertThat(rsp).isEqualTo(JOB_ID_JSON);
307 url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=JUNK";
308 rsp = restClient().get(url).block();
309 assertThat(rsp).isEqualTo("[]");
313 void a1eGetEiJob() throws Exception {
314 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
315 putEiJob(TYPE_ID, "jobId");
316 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
317 String rsp = restClient().get(url).block();
318 A1eEiJobInfo info = gson.fromJson(rsp, A1eEiJobInfo.class);
319 assertThat(info.owner).isEqualTo("owner");
320 assertThat(info.eiTypeId).isEqualTo(TYPE_ID);
324 void consumerGetEiJob() throws Exception {
325 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
326 putEiJob(TYPE_ID, "jobId");
327 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
328 String rsp = restClient().get(url).block();
329 ConsumerJobInfo info = gson.fromJson(rsp, ConsumerJobInfo.class);
330 assertThat(info.owner).isEqualTo("owner");
331 assertThat(info.infoTypeId).isEqualTo(TYPE_ID);
335 void a1eGetEiJobNotFound() throws Exception {
336 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
337 String url = A1eConsts.API_ROOT + "/eijobs/junk";
338 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
342 void consumerGetInfoJobNotFound() throws Exception {
343 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
344 String url = ConsumerConsts.API_ROOT + "/info-jobs/junk";
345 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
349 void a1eGetEiJobStatus() throws Exception {
350 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
351 putEiJob(TYPE_ID, "jobId");
353 verifyJobStatus("jobId", "ENABLED");
357 void consumerGetEiJobStatus() throws Exception {
358 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
359 putEiJob(TYPE_ID, "jobId");
361 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId/status";
362 String rsp = restClient().get(url).block();
364 .contains("ENABLED") //
365 .contains(PRODUCER_ID);
367 ConsumerJobStatus status = gson.fromJson(rsp, ConsumerJobStatus.class);
368 assertThat(status.producers).contains(PRODUCER_ID);
372 void a1eDeleteEiJob() throws Exception {
373 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
374 putEiJob(TYPE_ID, "jobId");
375 assertThat(this.infoJobs.size()).isEqualTo(1);
376 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
377 restClient().delete(url).block();
378 assertThat(this.infoJobs.size()).isZero();
380 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
381 await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped.size()).isEqualTo(1));
382 assertThat(simulatorResults.jobsStopped.get(0)).isEqualTo("jobId");
386 void consumerDeleteEiJob() throws Exception {
387 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
388 putEiJob(TYPE_ID, "jobId");
389 assertThat(this.infoJobs.size()).isEqualTo(1);
390 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
391 restClient().delete(url).block();
392 assertThat(this.infoJobs.size()).isZero();
394 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
395 await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped.size()).isEqualTo(1));
396 assertThat(simulatorResults.jobsStopped.get(0)).isEqualTo("jobId");
400 void a1eDeleteEiJobNotFound() throws Exception {
401 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
402 String url = A1eConsts.API_ROOT + "/eijobs/junk";
403 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
407 void consumerDeleteEiJobNotFound() throws Exception {
408 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
409 String url = ConsumerConsts.API_ROOT + "/info-jobs/junk";
410 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
414 void a1ePutEiJob() throws Exception {
415 // Test that one producer accepting a job is enough
416 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
417 putEiProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
419 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
420 String body = gson.toJson(infoJobInfo());
421 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
422 assertThat(this.infoJobs.size()).isEqualTo(1);
423 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
425 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
426 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
427 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
428 assertThat(request.id).isEqualTo("jobId");
430 // One retry --> two calls
431 await().untilAsserted(() -> assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2));
432 assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2);
434 resp = restClient().putForEntity(url, body).block();
435 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
436 InfoJob job = this.infoJobs.getJob("jobId");
437 assertThat(job.getOwner()).isEqualTo("owner");
439 verifyJobStatus(EI_JOB_ID, "ENABLED");
443 void consumerPutInformationJob() throws Exception {
444 // Test that one producer accepting a job is enough
445 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
447 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
448 String body = gson.toJson(consumerJobInfo());
449 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
450 assertThat(this.infoJobs.size()).isEqualTo(1);
451 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
453 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
454 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
455 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
456 assertThat(request.id).isEqualTo("jobId");
458 resp = restClient().putForEntity(url, body).block();
459 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
460 InfoJob job = this.infoJobs.getJob("jobId");
461 assertThat(job.getOwner()).isEqualTo("owner");
463 verifyJobStatus(EI_JOB_ID, "ENABLED");
467 void consumerPutInformationJob_noType() throws JsonMappingException, JsonProcessingException, ServiceException {
468 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId?typeCheck=false";
469 String body = gson.toJson(consumerJobInfo());
470 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
471 assertThat(this.infoJobs.size()).isEqualTo(1);
472 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
473 verifyJobStatus(EI_JOB_ID, "DISABLED");
475 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
477 verifyJobStatus(EI_JOB_ID, "ENABLED");
482 void a1ePutEiJob_jsonSchemavalidationError() throws Exception {
483 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
485 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
486 // The element with name "property1" is mandatory in the schema
487 A1eEiJobInfo jobInfo = new A1eEiJobInfo("typeId", jsonObject("{ \"XXstring\" : \"value\" }"), "owner",
488 "targetUri", "jobStatusUrl");
489 String body = gson.toJson(jobInfo);
491 testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Json validation failure");
495 void consumerPutJob_jsonSchemavalidationError() throws Exception {
496 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
498 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId?typeCheck=true";
499 // The element with name "property1" is mandatory in the schema
500 ConsumerJobInfo jobInfo =
501 new ConsumerJobInfo("typeId", jsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri", null);
502 String body = gson.toJson(jobInfo);
504 testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Json validation failure");
508 void consumerPutJob_uriError() throws Exception {
509 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
511 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId?typeCheck=true";
513 ConsumerJobInfo jobInfo = new ConsumerJobInfo(TYPE_ID, jsonObject(), "owner", "junk", null);
514 String body = gson.toJson(jobInfo);
516 testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "URI: junk is not absolute");
520 void a1eChangingEiTypeGetRejected() throws Exception {
521 putInfoProducerWithOneType("producer1", "typeId1");
522 putInfoProducerWithOneType("producer2", "typeId2");
523 putEiJob("typeId1", "jobId");
525 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
526 String body = gson.toJson(infoJobInfo("typeId2", "jobId"));
527 testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT,
528 "Not allowed to change type for existing EI job");
532 void consumerChangingInfoTypeGetRejected() throws Exception {
533 putInfoProducerWithOneType("producer1", "typeId1");
534 putInfoProducerWithOneType("producer2", "typeId2");
535 putEiJob("typeId1", "jobId");
537 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
538 String body = gson.toJson(consumerJobInfo("typeId2", "jobId"));
539 testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Not allowed to change type for existing job");
543 void producerPutEiType() throws JsonMappingException, JsonProcessingException, ServiceException {
544 assertThat(putInfoType(TYPE_ID)).isEqualTo(HttpStatus.CREATED);
545 assertThat(putInfoType(TYPE_ID)).isEqualTo(HttpStatus.OK);
549 void producerPutEiType_noSchema() {
550 String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID;
552 testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "No schema provided");
556 void producerDeleteEiType() throws Exception {
557 putInfoType(TYPE_ID);
558 deleteInfoType(TYPE_ID);
560 assertThat(this.infoTypes.size()).isZero();
562 testErrorCode(restClient().delete(deleteInfoTypeUrl(TYPE_ID)), HttpStatus.NOT_FOUND,
563 "Information type not found");
567 void producerDeleteEiTypeExistingProducer() throws Exception {
568 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
569 String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID;
570 testErrorCode(restClient().delete(url), HttpStatus.NOT_ACCEPTABLE,
571 "The type has active producers: " + PRODUCER_ID);
572 assertThat(this.infoTypes.size()).isEqualTo(1);
576 void producerPutProducerWithOneType_rejecting()
577 throws JsonMappingException, JsonProcessingException, ServiceException {
578 putEiProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
579 String url = A1eConsts.API_ROOT + "/eijobs/" + EI_JOB_ID;
580 String body = gson.toJson(infoJobInfo());
581 restClient().put(url, body).block();
583 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
584 // There is one retry -> 2 calls
585 await().untilAsserted(() -> assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2));
586 assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2);
588 verifyJobStatus(EI_JOB_ID, "DISABLED");
592 void producerGetEiProducerTypes() throws Exception {
593 final String EI_TYPE_ID_2 = TYPE_ID + "_2";
594 putInfoProducerWithOneType("producer1", TYPE_ID);
595 putEiJob(TYPE_ID, "jobId");
596 putInfoProducerWithOneType("producer2", EI_TYPE_ID_2);
597 putEiJob(EI_TYPE_ID_2, "jobId2");
598 String url = ProducerConsts.API_ROOT + "/info-types";
600 ResponseEntity<String> resp = restClient().getForEntity(url).block();
601 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
602 assertThat(resp.getBody()).contains(TYPE_ID);
603 assertThat(resp.getBody()).contains(EI_TYPE_ID_2);
607 void producerPutEiProducer() throws Exception {
608 this.putInfoType(TYPE_ID);
609 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
610 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
612 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
613 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
615 assertThat(this.infoTypes.size()).isEqualTo(1);
616 assertThat(this.infoProducers.getProducersForType(TYPE_ID)).hasSize(1);
617 assertThat(this.infoProducers.size()).isEqualTo(1);
618 assertThat(this.infoProducers.get("infoProducerId").getInfoTypes().iterator().next().getId())
621 resp = restClient().putForEntity(url, body).block();
622 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
624 resp = restClient().getForEntity(url).block();
625 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
626 assertThat(resp.getBody()).isEqualTo(body);
630 void producerPutEiProducerExistingJob() throws Exception {
631 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
632 putEiJob(TYPE_ID, "jobId");
633 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
634 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
635 restClient().putForEntity(url, body).block();
637 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
638 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(2));
639 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
640 assertThat(request.id).isEqualTo("jobId");
644 void testPutEiProducer_noType() throws Exception {
645 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
646 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
647 testErrorCode(restClient().put(url, body), HttpStatus.NOT_FOUND, "Information type not found");
651 void producerPutProducerAndEiJob() throws Exception {
652 this.putInfoType(TYPE_ID);
653 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
654 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
655 restClient().putForEntity(url, body).block();
656 assertThat(this.infoTypes.size()).isEqualTo(1);
657 this.infoTypes.getType(TYPE_ID);
659 url = A1eConsts.API_ROOT + "/eijobs/jobId";
660 body = gson.toJson(infoJobInfo());
661 restClient().putForEntity(url, body).block();
663 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
664 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
665 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
666 assertThat(request.id).isEqualTo("jobId");
670 void producerGetEiJobsForProducer() throws JsonMappingException, JsonProcessingException, ServiceException {
671 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
672 putEiJob(TYPE_ID, "jobId1");
673 putEiJob(TYPE_ID, "jobId2");
675 // PUT a consumerRestApiTestBase.java
676 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
677 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
678 restClient().putForEntity(url, body).block();
680 url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId/info-jobs";
681 ResponseEntity<String> resp = restClient().getForEntity(url).block();
682 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
684 ProducerJobInfo[] parsedResp = gson.fromJson(resp.getBody(), ProducerJobInfo[].class);
685 assertThat(parsedResp[0].typeId).isEqualTo(TYPE_ID);
686 assertThat(parsedResp[1].typeId).isEqualTo(TYPE_ID);
690 void producerDeleteEiProducer() throws Exception {
691 putInfoProducerWithOneType("infoProducerId", TYPE_ID);
692 putInfoProducerWithOneType("infoProducerId2", TYPE_ID);
694 assertThat(this.infoProducers.size()).isEqualTo(2);
695 InfoType type = this.infoTypes.getType(TYPE_ID);
696 assertThat(this.infoProducers.getProducerIdsForType(type.getId())).contains("infoProducerId");
697 assertThat(this.infoProducers.getProducerIdsForType(type.getId())).contains("infoProducerId2");
698 putEiJob(TYPE_ID, "jobId");
699 assertThat(this.infoJobs.size()).isEqualTo(1);
701 deleteEiProducer("infoProducerId");
702 assertThat(this.infoProducers.size()).isEqualTo(1);
703 assertThat(this.infoProducers.getProducerIdsForType(TYPE_ID)).doesNotContain("infoProducerId");
704 verifyJobStatus("jobId", "ENABLED");
706 deleteEiProducer("infoProducerId2");
707 assertThat(this.infoProducers.size()).isZero();
708 assertThat(this.infoTypes.size()).isEqualTo(1);
709 verifyJobStatus("jobId", "DISABLED");
713 void a1eJobStatusNotifications() throws JsonMappingException, JsonProcessingException, ServiceException {
714 ConsumerSimulatorController.TestResults consumerCalls = this.consumerSimulator.getTestResults();
715 ProducerSimulatorController.TestResults producerCalls = this.producerSimulator.getTestResults();
717 putInfoProducerWithOneType("infoProducerId", TYPE_ID);
718 putEiJob(TYPE_ID, "jobId");
719 putInfoProducerWithOneType("infoProducerId2", TYPE_ID);
720 await().untilAsserted(() -> assertThat(producerCalls.jobsStarted.size()).isEqualTo(2));
722 deleteEiProducer("infoProducerId2");
723 assertThat(this.infoTypes.size()).isEqualTo(1); // The type remains, one producer left
724 deleteEiProducer("infoProducerId");
725 assertThat(this.infoTypes.size()).isEqualTo(1); // The type remains
726 assertThat(this.infoJobs.size()).isEqualTo(1); // The job remains
727 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(1));
728 assertThat(consumerCalls.eiJobStatusCallbacks.get(0).state)
729 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED);
731 putInfoProducerWithOneType("infoProducerId", TYPE_ID);
732 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(2));
733 assertThat(consumerCalls.eiJobStatusCallbacks.get(1).state).isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
737 void a1eJobStatusNotifications2() throws JsonMappingException, JsonProcessingException, ServiceException {
738 // Test replacing a producer with new and removed types
741 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
742 putEiJob(TYPE_ID, EI_JOB_ID);
744 // change the type for the producer, the job shall be disabled
745 putInfoProducerWithOneType(PRODUCER_ID, "junk");
746 verifyJobStatus(EI_JOB_ID, "DISABLED");
747 ConsumerSimulatorController.TestResults consumerCalls = this.consumerSimulator.getTestResults();
748 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(1));
749 assertThat(consumerCalls.eiJobStatusCallbacks.get(0).state)
750 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED);
752 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
753 verifyJobStatus(EI_JOB_ID, "ENABLED");
754 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(2));
755 assertThat(consumerCalls.eiJobStatusCallbacks.get(1).state).isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
759 void producerGetProducerEiType() throws JsonMappingException, JsonProcessingException, ServiceException {
760 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
761 String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID;
762 ResponseEntity<String> resp = restClient().getForEntity(url).block();
763 ProducerInfoTypeInfo info = gson.fromJson(resp.getBody(), ProducerInfoTypeInfo.class);
764 assertThat(info.jobDataSchema).isNotNull();
768 void producerGetProducerIdentifiers() throws JsonMappingException, JsonProcessingException, ServiceException {
769 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
770 String url = ProducerConsts.API_ROOT + "/info-producers";
771 ResponseEntity<String> resp = restClient().getForEntity(url).block();
772 assertThat(resp.getBody()).contains(PRODUCER_ID);
774 url = ProducerConsts.API_ROOT + "/info-producers?info_type_id=" + TYPE_ID;
775 resp = restClient().getForEntity(url).block();
776 assertThat(resp.getBody()).contains(PRODUCER_ID);
778 url = ProducerConsts.API_ROOT + "/info-producers?info_type_id=junk";
779 resp = restClient().getForEntity(url).block();
780 assertThat(resp.getBody()).isEqualTo("[]");
784 void producerSupervision() throws JsonMappingException, JsonProcessingException, ServiceException {
786 ConsumerSimulatorController.TestResults consumerResults = this.consumerSimulator.getTestResults();
787 putEiProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
791 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
792 putEiJob(TYPE_ID, EI_JOB_ID);
793 verifyJobStatus(EI_JOB_ID, "ENABLED");
794 deleteEiProducer(PRODUCER_ID);
795 // A Job disabled status notification shall now be received
796 await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks.size()).isEqualTo(1));
797 assertThat(consumerResults.eiJobStatusCallbacks.get(0).state)
798 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED);
799 verifyJobStatus(EI_JOB_ID, "DISABLED");
802 assertThat(this.infoProducers.size()).isEqualTo(1);
803 assertThat(this.infoTypes.size()).isEqualTo(1);
804 assertProducerOpState("simulateProducerError", ProducerStatusInfo.OperationalState.ENABLED);
806 this.producerSupervision.createTask().blockLast();
807 this.producerSupervision.createTask().blockLast();
809 // Now we have one producer that is disabled
810 assertThat(this.infoProducers.size()).isEqualTo(1);
811 assertProducerOpState("simulateProducerError", ProducerStatusInfo.OperationalState.DISABLED);
813 // After 3 failed checks, the producer shall be deregistered
814 this.producerSupervision.createTask().blockLast();
815 assertThat(this.infoProducers.size()).isZero(); // The producer is removed
816 assertThat(this.infoTypes.size()).isEqualTo(1); // The type remains
818 // Now we have one disabled job, and no producer.
819 // PUT a producer, then a Job ENABLED status notification shall be received
820 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
821 await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks.size()).isEqualTo(2));
822 assertThat(consumerResults.eiJobStatusCallbacks.get(1).state)
823 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
824 verifyJobStatus(EI_JOB_ID, "ENABLED");
828 void producerSupervision2() throws JsonMappingException, JsonProcessingException, ServiceException {
829 // Test that supervision enables not enabled jobs and sends a notification when
832 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
833 putEiJob(TYPE_ID, EI_JOB_ID);
835 InfoProducer producer = this.infoProducers.getProducer(PRODUCER_ID);
836 InfoJob job = this.infoJobs.getJob(EI_JOB_ID);
837 // Pretend that the producer did reject the job and the a DISABLED notification
838 // is sent for the job
839 producer.setJobDisabled(job);
840 job.setLastReportedStatus(false);
841 verifyJobStatus(EI_JOB_ID, "DISABLED");
843 // Run the supervision and wait for the job to get started in the producer
844 this.producerSupervision.createTask().blockLast();
845 ConsumerSimulatorController.TestResults consumerResults = this.consumerSimulator.getTestResults();
846 await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks.size()).isEqualTo(1));
847 assertThat(consumerResults.eiJobStatusCallbacks.get(0).state)
848 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
849 verifyJobStatus(EI_JOB_ID, "ENABLED");
853 void testGetStatus() throws JsonMappingException, JsonProcessingException, ServiceException {
854 putEiProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
855 putEiProducerWithOneTypeRejecting("simulateProducerError2", TYPE_ID);
857 String url = "/status";
858 ResponseEntity<String> resp = restClient().getForEntity(url).block();
859 assertThat(resp.getBody()).contains("hunky dory");
863 void testEiJobDatabase() throws Exception {
864 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
865 putEiJob(TYPE_ID, "jobId1");
866 putEiJob(TYPE_ID, "jobId2");
868 assertThat(this.infoJobs.size()).isEqualTo(2);
871 InfoJob savedJob = this.infoJobs.getJob("jobId1");
873 InfoJobs jobs = new InfoJobs(this.applicationConfig, this.producerCallbacks);
874 jobs.restoreJobsFromDatabase();
875 assertThat(jobs.size()).isEqualTo(2);
876 InfoJob restoredJob = jobs.getJob("jobId1");
877 assertThat(restoredJob.getId()).isEqualTo("jobId1");
878 assertThat(restoredJob.getLastUpdated()).isEqualTo(savedJob.getLastUpdated());
880 jobs.remove("jobId1", this.infoProducers);
881 jobs.remove("jobId2", this.infoProducers);
884 // Restore the jobs, no jobs in database
885 InfoJobs jobs = new InfoJobs(this.applicationConfig, this.producerCallbacks);
886 jobs.restoreJobsFromDatabase();
887 assertThat(jobs.size()).isZero();
889 logger.warn("Test removing a job when the db file is gone");
890 this.infoJobs.remove("jobId1", this.infoProducers);
891 assertThat(this.infoJobs.size()).isEqualTo(1);
893 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
894 await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped.size()).isEqualTo(3));
898 void testEiTypesDatabase() throws Exception {
899 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
901 assertThat(this.infoTypes.size()).isEqualTo(1);
905 InfoTypes types = new InfoTypes(this.applicationConfig);
906 types.restoreTypesFromDatabase();
907 assertThat(types.size()).isEqualTo(1);
911 // Restore the jobs, no jobs in database
912 InfoTypes types = new InfoTypes(this.applicationConfig);
914 types.restoreTypesFromDatabase();
915 assertThat(types.size()).isZero();
917 logger.warn("Test removing a job when the db file is gone");
918 this.infoTypes.remove(this.infoTypes.getType(TYPE_ID));
919 assertThat(this.infoJobs.size()).isZero();
923 void testConsumerTypeSubscription() throws Exception {
925 final String callbackUrl = baseUrl() + ConsumerSimulatorController.getTypeStatusCallbackUrl();
926 final ConsumerTypeSubscriptionInfo info = new ConsumerTypeSubscriptionInfo(callbackUrl, "owner");
929 // PUT a subscription
930 String body = gson.toJson(info);
931 ResponseEntity<String> resp =
932 restClient().putForEntity(typeSubscriptionUrl() + "/subscriptionId", body).block();
933 assertThat(this.infoTypeSubscriptions.size()).isEqualTo(1);
934 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
935 resp = restClient().putForEntity(typeSubscriptionUrl() + "/subscriptionId", body).block();
936 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
940 ResponseEntity<String> resp = restClient().getForEntity(typeSubscriptionUrl()).block();
941 assertThat(resp.getBody()).isEqualTo("[\"subscriptionId\"]");
942 resp = restClient().getForEntity(typeSubscriptionUrl() + "?owner=owner").block();
943 assertThat(resp.getBody()).isEqualTo("[\"subscriptionId\"]");
944 resp = restClient().getForEntity(typeSubscriptionUrl() + "?owner=junk").block();
945 assertThat(resp.getBody()).isEqualTo("[]");
949 // GET the individual subscription
950 ResponseEntity<String> resp = restClient().getForEntity(typeSubscriptionUrl() + "/subscriptionId").block();
951 ConsumerTypeSubscriptionInfo respInfo = gson.fromJson(resp.getBody(), ConsumerTypeSubscriptionInfo.class);
952 assertThat(respInfo).isEqualTo(info);
956 // Test the callbacks
957 final ConsumerSimulatorController.TestResults consumerCalls = this.consumerSimulator.getTestResults();
959 // Test callback for PUT type
960 this.putInfoType(TYPE_ID);
961 await().untilAsserted(() -> assertThat(consumerCalls.typeRegistrationInfoCallbacks.size()).isEqualTo(1));
962 assertThat(consumerCalls.typeRegistrationInfoCallbacks.get(0).state)
963 .isEqualTo(ConsumerTypeRegistrationInfo.ConsumerTypeStatusValues.REGISTERED);
965 // Test callback for DELETE type
966 this.deleteInfoType(TYPE_ID);
967 await().untilAsserted(() -> assertThat(consumerCalls.typeRegistrationInfoCallbacks.size()).isEqualTo(2));
968 assertThat(consumerCalls.typeRegistrationInfoCallbacks.get(1).state)
969 .isEqualTo(ConsumerTypeRegistrationInfo.ConsumerTypeStatusValues.DEREGISTERED);
973 // DELETE the subscription
974 ResponseEntity<String> resp =
975 restClient().deleteForEntity(typeSubscriptionUrl() + "/subscriptionId").block();
976 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
977 assertThat(this.infoTypeSubscriptions.size()).isZero();
978 resp = restClient().getForEntity(typeSubscriptionUrl()).block();
979 assertThat(resp.getBody()).isEqualTo("[]");
984 void testTypeSubscriptionErrorCodes() throws Exception {
986 testErrorCode(restClient().get(typeSubscriptionUrl() + "/junk"), HttpStatus.NOT_FOUND,
987 "Could not find Information subscription: junk");
989 testErrorCode(restClient().delete(typeSubscriptionUrl() + "/junk"), HttpStatus.NOT_FOUND,
990 "Could not find Information subscription: junk");
993 private String typeSubscriptionUrl() {
994 return ConsumerConsts.API_ROOT + "/info-type-subscription";
997 private void deleteEiProducer(String infoProducerId) {
998 String url = ProducerConsts.API_ROOT + "/info-producers/" + infoProducerId;
999 restClient().deleteForEntity(url).block();
1002 private void verifyJobStatus(String jobId, String expStatus) {
1003 String url = A1eConsts.API_ROOT + "/eijobs/" + jobId + "/status";
1004 String rsp = restClient().get(url).block();
1005 assertThat(rsp).contains(expStatus);
1008 private void assertProducerOpState(String producerId,
1009 ProducerStatusInfo.OperationalState expectedOperationalState) {
1010 String statusUrl = ProducerConsts.API_ROOT + "/info-producers/" + producerId + "/status";
1011 ResponseEntity<String> resp = restClient().getForEntity(statusUrl).block();
1012 ProducerStatusInfo statusInfo = gson.fromJson(resp.getBody(), ProducerStatusInfo.class);
1013 assertThat(statusInfo.opState).isEqualTo(expectedOperationalState);
1016 ProducerInfoTypeInfo producerEiTypeRegistrationInfo(String typeId)
1017 throws JsonMappingException, JsonProcessingException {
1018 return new ProducerInfoTypeInfo(jsonSchemaObject());
1021 ProducerRegistrationInfo producerEiRegistratioInfoRejecting(String typeId)
1022 throws JsonMappingException, JsonProcessingException {
1023 return new ProducerRegistrationInfo(Arrays.asList(typeId), //
1024 baseUrl() + ProducerSimulatorController.JOB_ERROR_URL,
1025 baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL);
1028 ProducerRegistrationInfo producerInfoRegistratioInfo(String typeId)
1029 throws JsonMappingException, JsonProcessingException {
1030 return new ProducerRegistrationInfo(Arrays.asList(typeId), //
1031 baseUrl() + ProducerSimulatorController.JOB_URL, baseUrl() + ProducerSimulatorController.SUPERVISION_URL);
1034 private ConsumerJobInfo consumerJobInfo() throws JsonMappingException, JsonProcessingException {
1035 return consumerJobInfo(TYPE_ID, EI_JOB_ID);
1038 ConsumerJobInfo consumerJobInfo(String typeId, String infoJobId)
1039 throws JsonMappingException, JsonProcessingException {
1040 return new ConsumerJobInfo(typeId, jsonObject(), "owner", "https://junk.com",
1041 baseUrl() + ConsumerSimulatorController.getJobStatusUrl(infoJobId));
1044 private A1eEiJobInfo infoJobInfo() throws JsonMappingException, JsonProcessingException {
1045 return infoJobInfo(TYPE_ID, EI_JOB_ID);
1048 A1eEiJobInfo infoJobInfo(String typeId, String infoJobId) throws JsonMappingException, JsonProcessingException {
1049 return new A1eEiJobInfo(typeId, jsonObject(), "owner", "https://junk.com",
1050 baseUrl() + ConsumerSimulatorController.getJobStatusUrl(infoJobId));
1053 private Object jsonObject(String json) {
1055 return JsonParser.parseString(json).getAsJsonObject();
1056 } catch (Exception e) {
1057 throw new NullPointerException(e.toString());
1061 private Object jsonSchemaObject() {
1062 // a json schema with one mandatory property named "string"
1063 String schemaStr = "{" //
1064 + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," //
1065 + "\"type\": \"object\"," //
1066 + "\"properties\": {" //
1067 + EI_JOB_PROPERTY + " : {" //
1068 + " \"type\": \"string\"" //
1071 + "\"required\": [" //
1072 + EI_JOB_PROPERTY //
1075 return jsonObject(schemaStr);
1078 private Object jsonObject() {
1079 return jsonObject("{ " + EI_JOB_PROPERTY + " : \"value\" }");
1082 private InfoJob putEiJob(String infoTypeId, String jobId)
1083 throws JsonMappingException, JsonProcessingException, ServiceException {
1085 String url = A1eConsts.API_ROOT + "/eijobs/" + jobId;
1086 String body = gson.toJson(infoJobInfo(infoTypeId, jobId));
1087 restClient().putForEntity(url, body).block();
1089 return this.infoJobs.getJob(jobId);
1092 private HttpStatus putInfoType(String infoTypeId)
1093 throws JsonMappingException, JsonProcessingException, ServiceException {
1094 String url = ProducerConsts.API_ROOT + "/info-types/" + infoTypeId;
1095 String body = gson.toJson(producerEiTypeRegistrationInfo(infoTypeId));
1097 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
1098 this.infoTypes.getType(infoTypeId);
1099 return resp.getStatusCode();
1102 private String deleteInfoTypeUrl(String typeId) {
1103 return ProducerConsts.API_ROOT + "/info-types/" + typeId;
1106 private void deleteInfoType(String typeId) {
1107 restClient().delete(deleteInfoTypeUrl(typeId)).block();
1110 private InfoType putEiProducerWithOneTypeRejecting(String producerId, String infoTypeId)
1111 throws JsonMappingException, JsonProcessingException, ServiceException {
1112 this.putInfoType(infoTypeId);
1113 String url = ProducerConsts.API_ROOT + "/info-producers/" + producerId;
1114 String body = gson.toJson(producerEiRegistratioInfoRejecting(infoTypeId));
1115 restClient().putForEntity(url, body).block();
1116 return this.infoTypes.getType(infoTypeId);
1119 private InfoType putInfoProducerWithOneType(String producerId, String infoTypeId)
1120 throws JsonMappingException, JsonProcessingException, ServiceException {
1121 this.putInfoType(infoTypeId);
1123 String url = ProducerConsts.API_ROOT + "/info-producers/" + producerId;
1124 String body = gson.toJson(producerInfoRegistratioInfo(infoTypeId));
1126 restClient().putForEntity(url, body).block();
1128 return this.infoTypes.getType(infoTypeId);
1131 private String baseUrl() {
1132 return "https://localhost:" + this.port;
1135 private AsyncRestClient restClient(boolean useTrustValidation) {
1136 WebClientConfig config = this.applicationConfig.getWebClientConfig();
1137 HttpProxyConfig httpProxyConfig = ImmutableHttpProxyConfig.builder() //
1138 .httpProxyHost("") //
1139 .httpProxyPort(0) //
1141 config = ImmutableWebClientConfig.builder() //
1142 .keyStoreType(config.keyStoreType()) //
1143 .keyStorePassword(config.keyStorePassword()) //
1144 .keyStore(config.keyStore()) //
1145 .keyPassword(config.keyPassword()) //
1146 .isTrustStoreUsed(useTrustValidation) //
1147 .trustStore(config.trustStore()) //
1148 .trustStorePassword(config.trustStorePassword()) //
1149 .httpProxyConfig(httpProxyConfig).build();
1151 AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config);
1152 return restClientFactory.createRestClientNoHttpProxy(baseUrl());
1155 private AsyncRestClient restClient() {
1156 return restClient(false);
1159 private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) {
1160 testErrorCode(request, expStatus, responseContains, true);
1163 private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains,
1164 boolean expectApplicationProblemJsonMediaType) {
1165 StepVerifier.create(request) //
1166 .expectSubscription() //
1167 .expectErrorMatches(
1168 t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) //
1172 private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains,
1173 boolean expectApplicationProblemJsonMediaType) {
1174 assertTrue(throwable instanceof WebClientResponseException);
1175 WebClientResponseException responseException = (WebClientResponseException) throwable;
1176 assertThat(responseException.getStatusCode()).isEqualTo(expStatus);
1177 assertThat(responseException.getResponseBodyAsString()).contains(responseContains);
1178 if (expectApplicationProblemJsonMediaType) {
1179 assertThat(responseException.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON);