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.ics;
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.ics.clients.AsyncRestClient;
45 import org.oransc.ics.clients.AsyncRestClientFactory;
46 import org.oransc.ics.configuration.ApplicationConfig;
47 import org.oransc.ics.configuration.ImmutableHttpProxyConfig;
48 import org.oransc.ics.configuration.ImmutableWebClientConfig;
49 import org.oransc.ics.configuration.WebClientConfig;
50 import org.oransc.ics.configuration.WebClientConfig.HttpProxyConfig;
51 import org.oransc.ics.controller.ConsumerSimulatorController;
52 import org.oransc.ics.controller.ProducerSimulatorController;
53 import org.oransc.ics.controllers.a1e.A1eConsts;
54 import org.oransc.ics.controllers.a1e.A1eEiJobInfo;
55 import org.oransc.ics.controllers.a1e.A1eEiJobStatus;
56 import org.oransc.ics.controllers.a1e.A1eEiTypeInfo;
57 import org.oransc.ics.controllers.r1consumer.ConsumerConsts;
58 import org.oransc.ics.controllers.r1consumer.ConsumerInfoTypeInfo;
59 import org.oransc.ics.controllers.r1consumer.ConsumerJobInfo;
60 import org.oransc.ics.controllers.r1consumer.ConsumerJobStatus;
61 import org.oransc.ics.controllers.r1consumer.ConsumerTypeRegistrationInfo;
62 import org.oransc.ics.controllers.r1consumer.ConsumerTypeSubscriptionInfo;
63 import org.oransc.ics.controllers.r1producer.ProducerCallbacks;
64 import org.oransc.ics.controllers.r1producer.ProducerConsts;
65 import org.oransc.ics.controllers.r1producer.ProducerInfoTypeInfo;
66 import org.oransc.ics.controllers.r1producer.ProducerJobInfo;
67 import org.oransc.ics.controllers.r1producer.ProducerRegistrationInfo;
68 import org.oransc.ics.controllers.r1producer.ProducerStatusInfo;
69 import org.oransc.ics.exceptions.ServiceException;
70 import org.oransc.ics.repository.InfoJob;
71 import org.oransc.ics.repository.InfoJobs;
72 import org.oransc.ics.repository.InfoProducer;
73 import org.oransc.ics.repository.InfoProducers;
74 import org.oransc.ics.repository.InfoType;
75 import org.oransc.ics.repository.InfoTypeSubscriptions;
76 import org.oransc.ics.repository.InfoTypes;
77 import org.oransc.ics.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.infoTypeSubscriptions.clear();
166 this.producerSimulator.getTestResults().reset();
167 this.consumerSimulator.getTestResults().reset();
172 assertThat(this.producerSimulator.getTestResults().errorFound).isFalse();
176 void generateApiDoc() throws FileNotFoundException {
177 String url = "/v3/api-docs";
178 ResponseEntity<String> resp = restClient().getForEntity(url).block();
179 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
181 JSONObject jsonObj = new JSONObject(resp.getBody());
182 assertThat(jsonObj.remove("servers")).isNotNull();
184 String indented = jsonObj.toString(4);
185 try (PrintStream out = new PrintStream(new FileOutputStream("api/ics-api.json"))) {
191 void a1eGetEiTypes() throws Exception {
192 putInfoProducerWithOneType(PRODUCER_ID, "test");
193 String url = A1eConsts.API_ROOT + "/eitypes";
194 String rsp = restClient().get(url).block();
195 assertThat(rsp).isEqualTo("[\"test\"]");
199 void consumerGetInfoTypes() throws Exception {
200 putInfoProducerWithOneType(PRODUCER_ID, "test");
201 String url = ConsumerConsts.API_ROOT + "/info-types";
202 String rsp = restClient().get(url).block();
203 assertThat(rsp).isEqualTo("[\"test\"]");
207 void a1eGetEiTypesEmpty() throws Exception {
208 String url = A1eConsts.API_ROOT + "/eitypes";
209 String rsp = restClient().get(url).block();
210 assertThat(rsp).isEqualTo("[]");
214 void consumerGetEiTypesEmpty() throws Exception {
215 String url = ConsumerConsts.API_ROOT + "/info-types";
216 String rsp = restClient().get(url).block();
217 assertThat(rsp).isEqualTo("[]");
221 void a1eGetEiType() throws Exception {
222 putInfoProducerWithOneType(PRODUCER_ID, "test");
223 String url = A1eConsts.API_ROOT + "/eitypes/test";
224 String rsp = restClient().get(url).block();
225 A1eEiTypeInfo info = gson.fromJson(rsp, A1eEiTypeInfo.class);
226 assertThat(info).isNotNull();
230 void consumerGetEiType() throws Exception {
231 putInfoProducerWithOneType(PRODUCER_ID, "test");
232 String url = ConsumerConsts.API_ROOT + "/info-types/test";
233 String rsp = restClient().get(url).block();
234 ConsumerInfoTypeInfo info = gson.fromJson(rsp, ConsumerInfoTypeInfo.class);
235 assertThat(info).isNotNull();
236 assertThat(info.jobDataSchema).isNotNull();
237 assertThat(info.state).isEqualTo(ConsumerInfoTypeInfo.ConsumerTypeStatusValues.ENABLED);
238 assertThat(info.noOfProducers).isEqualTo(1);
242 void a1eGetEiTypeNotFound() throws Exception {
243 String url = A1eConsts.API_ROOT + "/eitypes/junk";
244 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Information type not found: junk");
248 void consumerGetEiTypeNotFound() throws Exception {
249 String url = ConsumerConsts.API_ROOT + "/info-types/junk";
250 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Information type not found: junk");
254 void a1eGetEiJobsIds() throws Exception {
255 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
256 putInfoJob(TYPE_ID, "jobId");
257 final String JOB_ID_JSON = "[\"jobId\"]";
258 String url = A1eConsts.API_ROOT + "/eijobs?infoTypeId=typeId";
259 String rsp = restClient().get(url).block();
260 assertThat(rsp).isEqualTo(JOB_ID_JSON);
262 url = A1eConsts.API_ROOT + "/eijobs?owner=owner";
263 rsp = restClient().get(url).block();
264 assertThat(rsp).isEqualTo(JOB_ID_JSON);
266 url = A1eConsts.API_ROOT + "/eijobs?owner=JUNK";
267 rsp = restClient().get(url).block();
268 assertThat(rsp).isEqualTo("[]");
270 url = A1eConsts.API_ROOT + "/eijobs";
271 rsp = restClient().get(url).block();
272 assertThat(rsp).isEqualTo(JOB_ID_JSON);
274 url = A1eConsts.API_ROOT + "/eijobs?eiTypeId=typeId&&owner=owner";
275 rsp = restClient().get(url).block();
276 assertThat(rsp).isEqualTo(JOB_ID_JSON);
278 url = A1eConsts.API_ROOT + "/eijobs?eiTypeId=JUNK";
279 rsp = restClient().get(url).block();
280 assertThat(rsp).isEqualTo("[]");
284 void consumerGetInformationJobsIds() throws Exception {
285 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
286 putInfoJob(TYPE_ID, "jobId");
287 final String JOB_ID_JSON = "[\"jobId\"]";
288 String url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=typeId";
289 String rsp = restClient().get(url).block();
290 assertThat(rsp).isEqualTo(JOB_ID_JSON);
292 url = ConsumerConsts.API_ROOT + "/info-jobs?owner=owner";
293 rsp = restClient().get(url).block();
294 assertThat(rsp).isEqualTo(JOB_ID_JSON);
296 url = ConsumerConsts.API_ROOT + "/info-jobs?owner=JUNK";
297 rsp = restClient().get(url).block();
298 assertThat(rsp).isEqualTo("[]");
300 url = ConsumerConsts.API_ROOT + "/info-jobs";
301 rsp = restClient().get(url).block();
302 assertThat(rsp).isEqualTo(JOB_ID_JSON);
304 url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=typeId&&owner=owner";
305 rsp = restClient().get(url).block();
306 assertThat(rsp).isEqualTo(JOB_ID_JSON);
308 url = ConsumerConsts.API_ROOT + "/info-jobs?infoTypeId=JUNK";
309 rsp = restClient().get(url).block();
310 assertThat(rsp).isEqualTo("[]");
314 void a1eGetEiJob() throws Exception {
315 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
316 putInfoJob(TYPE_ID, "jobId");
317 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
318 String rsp = restClient().get(url).block();
319 A1eEiJobInfo info = gson.fromJson(rsp, A1eEiJobInfo.class);
320 assertThat(info.owner).isEqualTo("owner");
321 assertThat(info.eiTypeId).isEqualTo(TYPE_ID);
325 void consumerGetEiJob() throws Exception {
326 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
327 putInfoJob(TYPE_ID, "jobId");
328 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
329 String rsp = restClient().get(url).block();
330 ConsumerJobInfo info = gson.fromJson(rsp, ConsumerJobInfo.class);
331 assertThat(info.owner).isEqualTo("owner");
332 assertThat(info.infoTypeId).isEqualTo(TYPE_ID);
336 void a1eGetEiJobNotFound() throws Exception {
337 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
338 String url = A1eConsts.API_ROOT + "/eijobs/junk";
339 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
343 void consumerGetInfoJobNotFound() throws Exception {
344 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
345 String url = ConsumerConsts.API_ROOT + "/info-jobs/junk";
346 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
350 void a1eGetEiJobStatus() throws Exception {
351 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
352 putInfoJob(TYPE_ID, "jobId");
354 verifyJobStatus("jobId", "ENABLED");
358 void consumerGetInfoJobStatus() throws Exception {
359 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
360 putInfoJob(TYPE_ID, "jobId");
362 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId/status";
363 String rsp = restClient().get(url).block();
365 .contains("ENABLED") //
366 .contains(PRODUCER_ID);
368 ConsumerJobStatus status = gson.fromJson(rsp, ConsumerJobStatus.class);
369 assertThat(status.producers).contains(PRODUCER_ID);
373 void a1eDeleteEiJob() throws Exception {
374 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
375 putInfoJob(TYPE_ID, "jobId");
376 assertThat(this.infoJobs.size()).isEqualTo(1);
377 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
378 restClient().delete(url).block();
379 assertThat(this.infoJobs.size()).isZero();
381 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
382 await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped.size()).isEqualTo(1));
383 assertThat(simulatorResults.jobsStopped.get(0)).isEqualTo("jobId");
387 void consumerDeleteEiJob() throws Exception {
388 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
389 putInfoJob(TYPE_ID, "jobId");
390 assertThat(this.infoJobs.size()).isEqualTo(1);
391 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
392 restClient().delete(url).block();
393 assertThat(this.infoJobs.size()).isZero();
395 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
396 await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped.size()).isEqualTo(1));
397 assertThat(simulatorResults.jobsStopped.get(0)).isEqualTo("jobId");
399 testErrorCode(restClient().delete(url), HttpStatus.NOT_FOUND, "Could not find Information job: jobId");
403 void a1eDeleteEiJobNotFound() throws Exception {
404 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
405 String url = A1eConsts.API_ROOT + "/eijobs/junk";
406 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
410 void consumerDeleteEiJobNotFound() throws Exception {
411 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
412 String url = ConsumerConsts.API_ROOT + "/info-jobs/junk";
413 testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND, "Could not find Information job: junk");
417 void a1ePutEiJob() throws Exception {
418 // Test that one producer accepting a job is enough
419 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
420 putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
422 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
423 String body = gson.toJson(infoJobInfo());
424 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
425 assertThat(this.infoJobs.size()).isEqualTo(1);
426 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
428 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
429 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
430 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
431 assertThat(request.id).isEqualTo("jobId");
433 // One retry --> two calls
434 await().untilAsserted(() -> assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2));
435 assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2);
437 resp = restClient().putForEntity(url, body).block();
438 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
439 InfoJob job = this.infoJobs.getJob("jobId");
440 assertThat(job.getOwner()).isEqualTo("owner");
442 verifyJobStatus(EI_JOB_ID, "ENABLED");
446 void consumerPutInformationJob() throws Exception {
447 // Test that one producer accepting a job is enough
448 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
450 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
451 String body = gson.toJson(consumerJobInfo());
452 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
453 assertThat(this.infoJobs.size()).isEqualTo(1);
454 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
456 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
457 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
458 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
459 assertThat(request.id).isEqualTo("jobId");
461 resp = restClient().putForEntity(url, body).block();
462 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
463 InfoJob job = this.infoJobs.getJob("jobId");
464 assertThat(job.getOwner()).isEqualTo("owner");
466 verifyJobStatus(EI_JOB_ID, "ENABLED");
470 void consumerPutInformationJob_noType() throws JsonMappingException, JsonProcessingException, ServiceException {
471 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId?typeCheck=false";
472 String body = gson.toJson(consumerJobInfo());
473 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
474 assertThat(this.infoJobs.size()).isEqualTo(1);
475 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
476 verifyJobStatus(EI_JOB_ID, "DISABLED");
478 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
480 verifyJobStatus(EI_JOB_ID, "ENABLED");
484 void a1ePutEiJob_jsonSchemavalidationError() throws Exception {
485 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
487 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
488 // The element with name "property1" is mandatory in the schema
489 A1eEiJobInfo jobInfo = new A1eEiJobInfo("typeId", jsonObject("{ \"XXstring\" : \"value\" }"), "owner",
490 "targetUri", "jobStatusUrl");
491 String body = gson.toJson(jobInfo);
493 testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "Json validation failure");
495 testErrorCode(restClient().put(url, "{jojo}"), HttpStatus.BAD_REQUEST, "", false);
500 void consumerPutJob_jsonSchemavalidationError() throws Exception {
501 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
503 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId?typeCheck=true";
504 // The element with name "property1" is mandatory in the schema
505 ConsumerJobInfo jobInfo =
506 new ConsumerJobInfo("typeId", jsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri", null);
507 String body = gson.toJson(jobInfo);
509 testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "Json validation failure");
513 void consumerPutJob_uriError() throws Exception {
514 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
516 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId?typeCheck=true";
518 ConsumerJobInfo jobInfo = new ConsumerJobInfo(TYPE_ID, jsonObject(), "owner", "junk", null);
519 String body = gson.toJson(jobInfo);
521 testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "URI: junk is not absolute");
525 void a1eChangingEiTypeGetRejected() throws Exception {
526 putInfoProducerWithOneType("producer1", "typeId1");
527 putInfoProducerWithOneType("producer2", "typeId2");
528 putInfoJob("typeId1", "jobId");
530 String url = A1eConsts.API_ROOT + "/eijobs/jobId";
531 String body = gson.toJson(infoJobInfo("typeId2", "jobId"));
532 testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT,
533 "Not allowed to change type for existing EI job");
537 void consumerChangingInfoTypeGetRejected() throws Exception {
538 putInfoProducerWithOneType("producer1", "typeId1");
539 putInfoProducerWithOneType("producer2", "typeId2");
540 putInfoJob("typeId1", "jobId");
542 String url = ConsumerConsts.API_ROOT + "/info-jobs/jobId";
543 String body = gson.toJson(consumerJobInfo("typeId2", "jobId"));
544 testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Not allowed to change type for existing job");
548 void producerPutEiType() throws JsonMappingException, JsonProcessingException, ServiceException {
549 assertThat(putInfoType(TYPE_ID)).isEqualTo(HttpStatus.CREATED);
550 assertThat(putInfoType(TYPE_ID)).isEqualTo(HttpStatus.OK);
554 void producerPutEiType_noSchema() {
555 String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID;
557 testErrorCode(restClient().put(url, body), HttpStatus.BAD_REQUEST, "No schema provided");
559 testErrorCode(restClient().post(url, body), HttpStatus.METHOD_NOT_ALLOWED, "", false);
563 void producerDeleteEiType() throws Exception {
564 putInfoType(TYPE_ID);
565 this.putInfoJob(TYPE_ID, "job1");
566 this.putInfoJob(TYPE_ID, "job2");
567 deleteInfoType(TYPE_ID);
569 assertThat(this.infoTypes.size()).isZero();
570 assertThat(this.infoJobs.size()).isZero(); // Test that also the job is deleted
572 testErrorCode(restClient().delete(deleteInfoTypeUrl(TYPE_ID)), HttpStatus.NOT_FOUND,
573 "Information type not found");
577 void producerDeleteEiTypeExistingProducer() throws Exception {
578 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
579 String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID;
580 testErrorCode(restClient().delete(url), HttpStatus.CONFLICT, "The type has active producers: " + PRODUCER_ID);
581 assertThat(this.infoTypes.size()).isEqualTo(1);
585 void producerPutProducerWithOneType_rejecting()
586 throws JsonMappingException, JsonProcessingException, ServiceException {
587 putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
588 String url = A1eConsts.API_ROOT + "/eijobs/" + EI_JOB_ID;
589 String body = gson.toJson(infoJobInfo());
590 restClient().put(url, body).block();
592 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
593 // There is one retry -> 2 calls
594 await().untilAsserted(() -> assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2));
595 assertThat(simulatorResults.noOfRejectedCreate).isEqualTo(2);
597 verifyJobStatus(EI_JOB_ID, "DISABLED");
601 void producerGetInfoProducerTypes() throws Exception {
602 final String EI_TYPE_ID_2 = TYPE_ID + "_2";
603 putInfoProducerWithOneType("producer1", TYPE_ID);
604 putInfoJob(TYPE_ID, "jobId");
605 putInfoProducerWithOneType("producer2", EI_TYPE_ID_2);
606 putInfoJob(EI_TYPE_ID_2, "jobId2");
607 String url = ProducerConsts.API_ROOT + "/info-types";
609 ResponseEntity<String> resp = restClient().getForEntity(url).block();
610 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
611 assertThat(resp.getBody()).contains(TYPE_ID);
612 assertThat(resp.getBody()).contains(EI_TYPE_ID_2);
616 void producerPutInfoProducer() throws Exception {
617 this.putInfoType(TYPE_ID);
618 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
619 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
621 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
622 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
624 assertThat(this.infoTypes.size()).isEqualTo(1);
625 assertThat(this.infoProducers.getProducersForType(TYPE_ID)).hasSize(1);
626 assertThat(this.infoProducers.size()).isEqualTo(1);
627 assertThat(this.infoProducers.get("infoProducerId").getInfoTypes().iterator().next().getId())
630 resp = restClient().putForEntity(url, body).block();
631 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
634 resp = restClient().getForEntity(url).block();
635 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
636 assertThat(resp.getBody()).isEqualTo(body);
638 testErrorCode(restClient().get(url + "junk"), HttpStatus.NOT_FOUND, "Could not find Information Producer");
642 void producerPutInfoProducerExistingJob() throws Exception {
643 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
644 putInfoJob(TYPE_ID, "jobId");
645 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
646 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
647 restClient().putForEntity(url, body).block();
649 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
650 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(2));
651 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
652 assertThat(request.id).isEqualTo("jobId");
656 void testPutInfoProducer_noType() throws Exception {
657 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
658 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
659 testErrorCode(restClient().put(url, body), HttpStatus.NOT_FOUND, "Information type not found");
663 void producerPutProducerAndInfoJob() throws Exception {
664 this.putInfoType(TYPE_ID);
665 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
666 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
667 restClient().putForEntity(url, body).block();
668 assertThat(this.infoTypes.size()).isEqualTo(1);
669 this.infoTypes.getType(TYPE_ID);
671 url = A1eConsts.API_ROOT + "/eijobs/jobId";
672 body = gson.toJson(infoJobInfo());
673 restClient().putForEntity(url, body).block();
675 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
676 await().untilAsserted(() -> assertThat(simulatorResults.jobsStarted.size()).isEqualTo(1));
677 ProducerJobInfo request = simulatorResults.jobsStarted.get(0);
678 assertThat(request.id).isEqualTo("jobId");
682 void producerGetInfoJobsForProducer() throws JsonMappingException, JsonProcessingException, ServiceException {
683 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
684 putInfoJob(TYPE_ID, "jobId1");
685 putInfoJob(TYPE_ID, "jobId2");
687 // PUT a consumerRestApiTestBase.java
688 String url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId";
689 String body = gson.toJson(producerInfoRegistratioInfo(TYPE_ID));
690 restClient().putForEntity(url, body).block();
692 url = ProducerConsts.API_ROOT + "/info-producers/infoProducerId/info-jobs";
693 ResponseEntity<String> resp = restClient().getForEntity(url).block();
694 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
696 ProducerJobInfo[] parsedResp = gson.fromJson(resp.getBody(), ProducerJobInfo[].class);
697 assertThat(parsedResp[0].typeId).isEqualTo(TYPE_ID);
698 assertThat(parsedResp[1].typeId).isEqualTo(TYPE_ID);
702 void producerDeleteInfoProducer() throws Exception {
703 putInfoProducerWithOneType("infoProducerId", TYPE_ID);
704 putInfoProducerWithOneType("infoProducerId2", TYPE_ID);
706 assertThat(this.infoProducers.size()).isEqualTo(2);
707 InfoType type = this.infoTypes.getType(TYPE_ID);
708 assertThat(this.infoProducers.getProducerIdsForType(type.getId())).contains("infoProducerId");
709 assertThat(this.infoProducers.getProducerIdsForType(type.getId())).contains("infoProducerId2");
710 putInfoJob(TYPE_ID, "jobId");
711 assertThat(this.infoJobs.size()).isEqualTo(1);
713 deleteInfoProducer("infoProducerId");
714 assertThat(this.infoProducers.size()).isEqualTo(1);
715 assertThat(this.infoProducers.getProducerIdsForType(TYPE_ID)).doesNotContain("infoProducerId");
716 verifyJobStatus("jobId", "ENABLED");
718 deleteInfoProducer("infoProducerId2");
719 assertThat(this.infoProducers.size()).isZero();
720 assertThat(this.infoTypes.size()).isEqualTo(1);
721 verifyJobStatus("jobId", "DISABLED");
723 String url = ProducerConsts.API_ROOT + "/info-producers/" + "junk";
724 testErrorCode(restClient().delete(url), HttpStatus.NOT_FOUND, "Could not find Information Producer");
728 void a1eJobStatusNotifications() throws JsonMappingException, JsonProcessingException, ServiceException {
729 ConsumerSimulatorController.TestResults consumerCalls = this.consumerSimulator.getTestResults();
730 ProducerSimulatorController.TestResults producerCalls = this.producerSimulator.getTestResults();
732 putInfoProducerWithOneType("infoProducerId", TYPE_ID);
733 putInfoJob(TYPE_ID, "jobId");
734 putInfoProducerWithOneType("infoProducerId2", TYPE_ID);
735 await().untilAsserted(() -> assertThat(producerCalls.jobsStarted.size()).isEqualTo(2));
737 deleteInfoProducer("infoProducerId2");
738 assertThat(this.infoTypes.size()).isEqualTo(1); // The type remains, one producer left
739 deleteInfoProducer("infoProducerId");
740 assertThat(this.infoTypes.size()).isEqualTo(1); // The type remains
741 assertThat(this.infoJobs.size()).isEqualTo(1); // The job remains
742 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(1));
743 assertThat(consumerCalls.eiJobStatusCallbacks.get(0).state)
744 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED);
746 putInfoProducerWithOneType("infoProducerId", TYPE_ID);
747 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(2));
748 assertThat(consumerCalls.eiJobStatusCallbacks.get(1).state).isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
752 void a1eJobStatusNotifications2() throws JsonMappingException, JsonProcessingException, ServiceException {
753 // Test replacing a producer with new and removed types
756 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
757 putInfoJob(TYPE_ID, EI_JOB_ID);
759 // change the type for the producer, the job shall be disabled
760 putInfoProducerWithOneType(PRODUCER_ID, "junk");
761 verifyJobStatus(EI_JOB_ID, "DISABLED");
762 ConsumerSimulatorController.TestResults consumerCalls = this.consumerSimulator.getTestResults();
763 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(1));
764 assertThat(consumerCalls.eiJobStatusCallbacks.get(0).state)
765 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED);
767 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
768 verifyJobStatus(EI_JOB_ID, "ENABLED");
769 await().untilAsserted(() -> assertThat(consumerCalls.eiJobStatusCallbacks.size()).isEqualTo(2));
770 assertThat(consumerCalls.eiJobStatusCallbacks.get(1).state).isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
774 void producerGetProducerInfoType() throws JsonMappingException, JsonProcessingException, ServiceException {
775 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
776 String url = ProducerConsts.API_ROOT + "/info-types/" + TYPE_ID;
777 ResponseEntity<String> resp = restClient().getForEntity(url).block();
778 ProducerInfoTypeInfo info = gson.fromJson(resp.getBody(), ProducerInfoTypeInfo.class);
779 assertThat(info.jobDataSchema).isNotNull();
780 assertThat(info.typeSpecificInformation).isNotNull();
782 testErrorCode(restClient().get(url + "junk"), HttpStatus.NOT_FOUND, "Information type not found");
786 void producerGetProducerIdentifiers() throws JsonMappingException, JsonProcessingException, ServiceException {
787 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
788 String url = ProducerConsts.API_ROOT + "/info-producers";
789 ResponseEntity<String> resp = restClient().getForEntity(url).block();
790 assertThat(resp.getBody()).contains(PRODUCER_ID);
792 url = ProducerConsts.API_ROOT + "/info-producers?info_type_id=" + TYPE_ID;
793 resp = restClient().getForEntity(url).block();
794 assertThat(resp.getBody()).contains(PRODUCER_ID);
796 url = ProducerConsts.API_ROOT + "/info-producers?info_type_id=junk";
797 resp = restClient().getForEntity(url).block();
798 assertThat(resp.getBody()).isEqualTo("[]");
802 void producerSupervision() throws JsonMappingException, JsonProcessingException, ServiceException {
804 ConsumerSimulatorController.TestResults consumerResults = this.consumerSimulator.getTestResults();
805 putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
809 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
810 putInfoJob(TYPE_ID, EI_JOB_ID);
811 verifyJobStatus(EI_JOB_ID, "ENABLED");
812 deleteInfoProducer(PRODUCER_ID);
813 // A Job disabled status notification shall now be received
814 await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks.size()).isEqualTo(1));
815 assertThat(consumerResults.eiJobStatusCallbacks.get(0).state)
816 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.DISABLED);
817 verifyJobStatus(EI_JOB_ID, "DISABLED");
820 assertThat(this.infoProducers.size()).isEqualTo(1);
821 assertThat(this.infoTypes.size()).isEqualTo(1);
822 assertProducerOpState("simulateProducerError", ProducerStatusInfo.OperationalState.ENABLED);
824 this.producerSupervision.createTask().blockLast();
825 this.producerSupervision.createTask().blockLast();
827 // Now we have one producer that is disabled
828 assertThat(this.infoProducers.size()).isEqualTo(1);
829 assertProducerOpState("simulateProducerError", ProducerStatusInfo.OperationalState.DISABLED);
831 // After 3 failed checks, the producer shall be deregistered
832 this.producerSupervision.createTask().blockLast();
833 assertThat(this.infoProducers.size()).isZero(); // The producer is removed
834 assertThat(this.infoTypes.size()).isEqualTo(1); // The type remains
836 // Now we have one disabled job, and no producer.
837 // PUT a producer, then a Job ENABLED status notification shall be received
838 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
839 await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks.size()).isEqualTo(2));
840 assertThat(consumerResults.eiJobStatusCallbacks.get(1).state)
841 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
842 verifyJobStatus(EI_JOB_ID, "ENABLED");
846 void producerSupervision2() throws JsonMappingException, JsonProcessingException, ServiceException {
847 // Test that supervision enables not enabled jobs and sends a notification when
850 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
851 putInfoJob(TYPE_ID, EI_JOB_ID);
853 InfoProducer producer = this.infoProducers.getProducer(PRODUCER_ID);
854 InfoJob job = this.infoJobs.getJob(EI_JOB_ID);
855 // Pretend that the producer did reject the job and the a DISABLED notification
856 // is sent for the job
857 producer.setJobDisabled(job);
858 job.setLastReportedStatus(false);
859 verifyJobStatus(EI_JOB_ID, "DISABLED");
861 // Run the supervision and wait for the job to get started in the producer
862 this.producerSupervision.createTask().blockLast();
863 ConsumerSimulatorController.TestResults consumerResults = this.consumerSimulator.getTestResults();
864 await().untilAsserted(() -> assertThat(consumerResults.eiJobStatusCallbacks.size()).isEqualTo(1));
865 assertThat(consumerResults.eiJobStatusCallbacks.get(0).state)
866 .isEqualTo(A1eEiJobStatus.EiJobStatusValues.ENABLED);
867 verifyJobStatus(EI_JOB_ID, "ENABLED");
871 void testGetStatus() throws JsonMappingException, JsonProcessingException, ServiceException {
872 putInfoProducerWithOneTypeRejecting("simulateProducerError", TYPE_ID);
873 putInfoProducerWithOneTypeRejecting("simulateProducerError2", TYPE_ID);
875 String url = "/status";
876 ResponseEntity<String> resp = restClient().getForEntity(url).block();
877 assertThat(resp.getBody()).contains("hunky dory");
881 void testEiJobDatabase() throws Exception {
882 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
883 putInfoJob(TYPE_ID, "jobId1");
884 putInfoJob(TYPE_ID, "jobId2");
886 assertThat(this.infoJobs.size()).isEqualTo(2);
889 InfoJob savedJob = this.infoJobs.getJob("jobId1");
891 InfoJobs jobs = new InfoJobs(this.applicationConfig, this.producerCallbacks);
892 jobs.restoreJobsFromDatabase();
893 assertThat(jobs.size()).isEqualTo(2);
894 InfoJob restoredJob = jobs.getJob("jobId1");
895 assertThat(restoredJob.getId()).isEqualTo("jobId1");
896 assertThat(restoredJob.getLastUpdated()).isEqualTo(savedJob.getLastUpdated());
898 jobs.remove("jobId1", this.infoProducers);
899 jobs.remove("jobId2", this.infoProducers);
902 // Restore the jobs, no jobs in database
903 InfoJobs jobs = new InfoJobs(this.applicationConfig, this.producerCallbacks);
904 jobs.restoreJobsFromDatabase();
905 assertThat(jobs.size()).isZero();
907 logger.warn("Test removing a job when the db file is gone");
908 this.infoJobs.remove("jobId1", this.infoProducers);
909 assertThat(this.infoJobs.size()).isEqualTo(1);
911 ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults();
912 await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped.size()).isEqualTo(3));
916 void testEiTypesDatabase() throws Exception {
917 putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID);
919 assertThat(this.infoTypes.size()).isEqualTo(1);
923 InfoTypes types = new InfoTypes(this.applicationConfig);
924 types.restoreTypesFromDatabase();
925 assertThat(types.size()).isEqualTo(1);
928 // Restore the jobs, no jobs in database
929 InfoTypes types = new InfoTypes(this.applicationConfig);
931 types.restoreTypesFromDatabase();
932 assertThat(types.size()).isZero();
934 logger.warn("Test removing a job when the db file is gone");
935 this.infoTypes.remove(this.infoTypes.getType(TYPE_ID));
936 assertThat(this.infoJobs.size()).isZero();
940 void testConsumerTypeSubscriptionDatabase() {
941 final String callbackUrl = baseUrl() + ConsumerSimulatorController.getTypeStatusCallbackUrl();
942 final ConsumerTypeSubscriptionInfo info = new ConsumerTypeSubscriptionInfo(callbackUrl, "owner");
944 // PUT a subscription
945 String body = gson.toJson(info);
946 restClient().putForEntity(typeSubscriptionUrl() + "/subscriptionId", body).block();
947 assertThat(this.infoTypeSubscriptions.size()).isEqualTo(1);
949 InfoTypeSubscriptions restoredSubscriptions = new InfoTypeSubscriptions(this.applicationConfig);
950 assertThat(restoredSubscriptions.size()).isEqualTo(1);
951 assertThat(restoredSubscriptions.getSubscriptionsForOwner("owner")).hasSize(1);
953 // Delete the subscription
954 restClient().deleteForEntity(typeSubscriptionUrl() + "/subscriptionId").block();
955 restoredSubscriptions = new InfoTypeSubscriptions(this.applicationConfig);
956 assertThat(restoredSubscriptions.size()).isZero();
960 void testConsumerTypeSubscription() throws Exception {
962 final String callbackUrl = baseUrl() + ConsumerSimulatorController.getTypeStatusCallbackUrl();
963 final ConsumerTypeSubscriptionInfo info = new ConsumerTypeSubscriptionInfo(callbackUrl, "owner");
965 testErrorCode(restClient().get(typeSubscriptionUrl() + "/junk"), HttpStatus.NOT_FOUND,
966 "Could not find Information subscription: junk");
968 testErrorCode(restClient().delete(typeSubscriptionUrl() + "/junk"), HttpStatus.NOT_FOUND,
969 "Could not find Information subscription: junk");
972 // PUT a subscription
973 String body = gson.toJson(info);
974 ResponseEntity<String> resp =
975 restClient().putForEntity(typeSubscriptionUrl() + "/subscriptionId", body).block();
976 assertThat(this.infoTypeSubscriptions.size()).isEqualTo(1);
977 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
978 resp = restClient().putForEntity(typeSubscriptionUrl() + "/subscriptionId", body).block();
979 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
983 ResponseEntity<String> resp = restClient().getForEntity(typeSubscriptionUrl()).block();
984 assertThat(resp.getBody()).isEqualTo("[\"subscriptionId\"]");
985 resp = restClient().getForEntity(typeSubscriptionUrl() + "?owner=owner").block();
986 assertThat(resp.getBody()).isEqualTo("[\"subscriptionId\"]");
987 resp = restClient().getForEntity(typeSubscriptionUrl() + "?owner=junk").block();
988 assertThat(resp.getBody()).isEqualTo("[]");
992 // GET the individual subscription
993 ResponseEntity<String> resp = restClient().getForEntity(typeSubscriptionUrl() + "/subscriptionId").block();
994 ConsumerTypeSubscriptionInfo respInfo = gson.fromJson(resp.getBody(), ConsumerTypeSubscriptionInfo.class);
995 assertThat(respInfo).isEqualTo(info);
999 // Test the callbacks
1000 final ConsumerSimulatorController.TestResults consumerCalls = this.consumerSimulator.getTestResults();
1002 // Test callback for PUT type
1003 this.putInfoType(TYPE_ID);
1004 await().untilAsserted(() -> assertThat(consumerCalls.typeRegistrationInfoCallbacks.size()).isEqualTo(1));
1005 assertThat(consumerCalls.typeRegistrationInfoCallbacks.get(0).state)
1006 .isEqualTo(ConsumerTypeRegistrationInfo.ConsumerTypeStatusValues.REGISTERED);
1008 // Test callback for DELETE type
1009 this.deleteInfoType(TYPE_ID);
1010 await().untilAsserted(() -> assertThat(consumerCalls.typeRegistrationInfoCallbacks.size()).isEqualTo(2));
1011 assertThat(consumerCalls.typeRegistrationInfoCallbacks.get(1).state)
1012 .isEqualTo(ConsumerTypeRegistrationInfo.ConsumerTypeStatusValues.DEREGISTERED);
1016 // DELETE the subscription
1017 ResponseEntity<String> resp =
1018 restClient().deleteForEntity(typeSubscriptionUrl() + "/subscriptionId").block();
1019 assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
1020 assertThat(this.infoTypeSubscriptions.size()).isZero();
1021 resp = restClient().getForEntity(typeSubscriptionUrl()).block();
1022 assertThat(resp.getBody()).isEqualTo("[]");
1027 void testRemovingNonWorkingSubscription() throws Exception {
1028 // Test that subscriptions are removed for a unresponsive consumer
1030 // PUT a subscription with a junk callback
1031 final ConsumerTypeSubscriptionInfo info = new ConsumerTypeSubscriptionInfo(baseUrl() + "/JUNK", "owner");
1032 String body = gson.toJson(info);
1033 restClient().putForEntity(typeSubscriptionUrl() + "/subscriptionId", body).block();
1034 assertThat(this.infoTypeSubscriptions.size()).isEqualTo(1);
1036 this.putInfoType(TYPE_ID);
1037 // The callback will fail and the subscription will be removed
1038 await().untilAsserted(() -> assertThat(this.infoTypeSubscriptions.size()).isZero());
1042 void testTypeSubscriptionErrorCodes() throws Exception {
1044 testErrorCode(restClient().get(typeSubscriptionUrl() + "/junk"), HttpStatus.NOT_FOUND,
1045 "Could not find Information subscription: junk");
1047 testErrorCode(restClient().delete(typeSubscriptionUrl() + "/junk"), HttpStatus.NOT_FOUND,
1048 "Could not find Information subscription: junk");
1051 private String typeSubscriptionUrl() {
1052 return ConsumerConsts.API_ROOT + "/info-type-subscription";
1055 private void deleteInfoProducer(String infoProducerId) {
1056 String url = ProducerConsts.API_ROOT + "/info-producers/" + infoProducerId;
1057 restClient().deleteForEntity(url).block();
1060 private void verifyJobStatus(String jobId, String expStatus) {
1061 String url = A1eConsts.API_ROOT + "/eijobs/" + jobId + "/status";
1062 String rsp = restClient().get(url).block();
1063 assertThat(rsp).contains(expStatus);
1066 private void assertProducerOpState(String producerId,
1067 ProducerStatusInfo.OperationalState expectedOperationalState) {
1068 String statusUrl = ProducerConsts.API_ROOT + "/info-producers/" + producerId + "/status";
1069 ResponseEntity<String> resp = restClient().getForEntity(statusUrl).block();
1070 ProducerStatusInfo statusInfo = gson.fromJson(resp.getBody(), ProducerStatusInfo.class);
1071 assertThat(statusInfo.opState).isEqualTo(expectedOperationalState);
1074 ProducerInfoTypeInfo ProducerInfoTypeRegistrationInfo(String typeId)
1075 throws JsonMappingException, JsonProcessingException {
1076 return new ProducerInfoTypeInfo(jsonSchemaObject(), typeSpecifcInfoObject());
1079 ProducerRegistrationInfo producerEiRegistratioInfoRejecting(String typeId)
1080 throws JsonMappingException, JsonProcessingException {
1081 return new ProducerRegistrationInfo(Arrays.asList(typeId), //
1082 baseUrl() + ProducerSimulatorController.JOB_ERROR_URL,
1083 baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL);
1086 ProducerRegistrationInfo producerInfoRegistratioInfo(String typeId)
1087 throws JsonMappingException, JsonProcessingException {
1088 return new ProducerRegistrationInfo(Arrays.asList(typeId), //
1089 baseUrl() + ProducerSimulatorController.JOB_URL, baseUrl() + ProducerSimulatorController.SUPERVISION_URL);
1092 private ConsumerJobInfo consumerJobInfo() throws JsonMappingException, JsonProcessingException {
1093 return consumerJobInfo(TYPE_ID, EI_JOB_ID);
1096 ConsumerJobInfo consumerJobInfo(String typeId, String infoJobId)
1097 throws JsonMappingException, JsonProcessingException {
1098 return new ConsumerJobInfo(typeId, jsonObject(), "owner", "https://junk.com",
1099 baseUrl() + ConsumerSimulatorController.getJobStatusUrl(infoJobId));
1102 private A1eEiJobInfo infoJobInfo() throws JsonMappingException, JsonProcessingException {
1103 return infoJobInfo(TYPE_ID, EI_JOB_ID);
1106 A1eEiJobInfo infoJobInfo(String typeId, String infoJobId) throws JsonMappingException, JsonProcessingException {
1107 return new A1eEiJobInfo(typeId, jsonObject(), "owner", "https://junk.com",
1108 baseUrl() + ConsumerSimulatorController.getJobStatusUrl(infoJobId));
1111 private Object jsonObject(String json) {
1113 return JsonParser.parseString(json).getAsJsonObject();
1114 } catch (Exception e) {
1115 throw new NullPointerException(e.toString());
1119 private Object typeSpecifcInfoObject() {
1120 return jsonObject("{ \"propertyName\" : \"value\" }");
1123 private Object jsonSchemaObject() {
1124 // a json schema with one mandatory property named "string"
1125 String schemaStr = "{" //
1126 + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," //
1127 + "\"type\": \"object\"," //
1128 + "\"properties\": {" //
1129 + EI_JOB_PROPERTY + " : {" //
1130 + " \"type\": \"string\"" //
1133 + "\"required\": [" //
1134 + EI_JOB_PROPERTY //
1137 return jsonObject(schemaStr);
1140 private Object jsonObject() {
1141 return jsonObject("{ " + EI_JOB_PROPERTY + " : \"value\" }");
1144 private InfoJob putInfoJob(String infoTypeId, String jobId)
1145 throws JsonMappingException, JsonProcessingException, ServiceException {
1147 String url = A1eConsts.API_ROOT + "/eijobs/" + jobId;
1148 String body = gson.toJson(infoJobInfo(infoTypeId, jobId));
1149 restClient().putForEntity(url, body).block();
1151 return this.infoJobs.getJob(jobId);
1154 private HttpStatus putInfoType(String infoTypeId)
1155 throws JsonMappingException, JsonProcessingException, ServiceException {
1156 String url = ProducerConsts.API_ROOT + "/info-types/" + infoTypeId;
1157 String body = gson.toJson(ProducerInfoTypeRegistrationInfo(infoTypeId));
1159 ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
1160 this.infoTypes.getType(infoTypeId);
1161 return resp.getStatusCode();
1164 private String deleteInfoTypeUrl(String typeId) {
1165 return ProducerConsts.API_ROOT + "/info-types/" + typeId;
1168 private void deleteInfoType(String typeId) {
1169 restClient().delete(deleteInfoTypeUrl(typeId)).block();
1172 private InfoType putInfoProducerWithOneTypeRejecting(String producerId, String infoTypeId)
1173 throws JsonMappingException, JsonProcessingException, ServiceException {
1174 this.putInfoType(infoTypeId);
1175 String url = ProducerConsts.API_ROOT + "/info-producers/" + producerId;
1176 String body = gson.toJson(producerEiRegistratioInfoRejecting(infoTypeId));
1177 restClient().putForEntity(url, body).block();
1178 return this.infoTypes.getType(infoTypeId);
1181 private InfoType putInfoProducerWithOneType(String producerId, String infoTypeId)
1182 throws JsonMappingException, JsonProcessingException, ServiceException {
1183 this.putInfoType(infoTypeId);
1185 String url = ProducerConsts.API_ROOT + "/info-producers/" + producerId;
1186 String body = gson.toJson(producerInfoRegistratioInfo(infoTypeId));
1188 restClient().putForEntity(url, body).block();
1190 return this.infoTypes.getType(infoTypeId);
1193 private String baseUrl() {
1194 return "https://localhost:" + this.port;
1197 private AsyncRestClient restClient(boolean useTrustValidation) {
1198 WebClientConfig config = this.applicationConfig.getWebClientConfig();
1199 HttpProxyConfig httpProxyConfig = ImmutableHttpProxyConfig.builder() //
1200 .httpProxyHost("") //
1201 .httpProxyPort(0) //
1203 config = ImmutableWebClientConfig.builder() //
1204 .keyStoreType(config.keyStoreType()) //
1205 .keyStorePassword(config.keyStorePassword()) //
1206 .keyStore(config.keyStore()) //
1207 .keyPassword(config.keyPassword()) //
1208 .isTrustStoreUsed(useTrustValidation) //
1209 .trustStore(config.trustStore()) //
1210 .trustStorePassword(config.trustStorePassword()) //
1211 .httpProxyConfig(httpProxyConfig).build();
1213 AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config);
1214 return restClientFactory.createRestClientNoHttpProxy(baseUrl());
1217 private AsyncRestClient restClient() {
1218 return restClient(false);
1221 private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) {
1222 testErrorCode(request, expStatus, responseContains, true);
1225 private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains,
1226 boolean expectApplicationProblemJsonMediaType) {
1227 StepVerifier.create(request) //
1228 .expectSubscription() //
1229 .expectErrorMatches(
1230 t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) //
1234 private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains,
1235 boolean expectApplicationProblemJsonMediaType) {
1236 assertTrue(throwable instanceof WebClientResponseException);
1237 WebClientResponseException responseException = (WebClientResponseException) throwable;
1238 assertThat(responseException.getStatusCode()).isEqualTo(expStatus);
1239 assertThat(responseException.getResponseBodyAsString()).contains(responseContains);
1240 if (expectApplicationProblemJsonMediaType) {
1241 assertThat(responseException.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON);