5ed8642abb955b57ee87a2ce6f28eee5a139e112
[ccsdk/oran.git] /
1 /*-
2  * ========================LICENSE_START=================================
3  * ONAP : ccsdk oran
4  * ======================================================================
5  * Copyright (C) 2019-2023 Nordix Foundation. All rights reserved.
6  * ======================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.awaitility.Awaitility.await;
25 import static org.junit.jupiter.api.Assertions.*;
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.Mockito.doReturn;
28
29 import com.fasterxml.jackson.core.JsonProcessingException;
30 import com.fasterxml.jackson.databind.ObjectMapper;
31
32 import java.lang.invoke.MethodHandles;
33 import java.nio.charset.StandardCharsets;
34 import java.nio.file.Files;
35 import java.nio.file.Path;
36 import java.time.Duration;
37 import java.time.Instant;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.HashMap;
43
44 import org.junit.jupiter.api.AfterAll;
45 import org.junit.jupiter.api.AfterEach;
46 import org.junit.jupiter.api.BeforeEach;
47 import org.junit.jupiter.api.DisplayName;
48 import org.junit.jupiter.api.MethodOrderer;
49 import org.junit.jupiter.api.Test;
50 import org.junit.jupiter.api.TestMethodOrder;
51 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
52 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
53 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory;
54 import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext;
55 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
56 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig.RicConfigUpdate;
57 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
58 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig;
59 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.OpenPolicyAgentSimulatorController;
60 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceCallbackInfo;
61 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest;
62 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest.Input.AccessType;
63 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
64 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.RicInfo;
65 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.PolicyTypeIdList;
66 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.PolicyInfo;
67 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.PolicyInfoList;
68 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.PolicyIdList;
69 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.PolicyStatusInfo;
70 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceStatusList;
71 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceStatus;
72 import org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceRegistrationInfo;
73 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock;
74 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
75 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
76 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
77 import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
78 import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
79 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
80 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
81 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
82 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service;
83 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
84 import org.onap.ccsdk.oran.a1policymanagementservice.tasks.RefreshConfigTask;
85 import org.onap.ccsdk.oran.a1policymanagementservice.tasks.RicSupervision;
86 import org.onap.ccsdk.oran.a1policymanagementservice.tasks.ServiceSupervision;
87 import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1Client;
88 import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1ClientFactory;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91 import org.springframework.beans.factory.annotation.Autowired;
92 import org.springframework.boot.test.context.SpringBootTest;
93 import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
94 import org.springframework.boot.test.context.TestConfiguration;
95 import org.springframework.boot.test.web.server.LocalServerPort;
96 import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
97 import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
98 import org.springframework.context.ApplicationContext;
99 import org.springframework.context.annotation.Bean;
100 import org.springframework.http.HttpStatus;
101 import org.springframework.http.MediaType;
102 import org.springframework.http.ResponseEntity;
103 import org.springframework.test.context.TestPropertySource;
104 import org.springframework.util.FileSystemUtils;
105 import org.springframework.web.reactive.function.client.WebClientResponseException;
106
107 import reactor.core.publisher.Mono;
108 import reactor.test.StepVerifier;
109 import reactor.util.annotation.Nullable;
110
111 @TestMethodOrder(MethodOrderer.MethodName.class)
112 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
113 @TestPropertySource(properties = { //
114         "server.ssl.key-store=./config/keystore.jks", //
115         "app.webclient.trust-store=./config/truststore.jks", //
116         "app.webclient.trust-store-used=true", //
117         "app.vardata-directory=/tmp/pmstest", //
118         "app.filepath=", //
119         "app.s3.bucket=" // If this is set, S3 will be used to store data.
120 })
121 class ApplicationTest {
122     private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
123
124     @Autowired
125     ApplicationContext context;
126
127     @Autowired
128     private Rics rics;
129
130     @Autowired
131     private Policies policies;
132
133     @Autowired
134     private PolicyTypes policyTypes;
135
136     @Autowired
137     MockA1ClientFactory a1ClientFactory;
138
139     @Autowired
140     private ObjectMapper objectMapper;
141
142     @Autowired
143     RicSupervision supervision;
144
145     @Autowired
146     ApplicationConfig applicationConfig;
147
148     @Autowired
149     Services services;
150
151     @Autowired
152     RappSimulatorController rAppSimulator;
153
154     @Autowired
155     RefreshConfigTask refreshConfigTask;
156
157     @Autowired
158     SecurityContext securityContext;
159
160     @Autowired
161     OpenPolicyAgentSimulatorController openPolicyAgentSimulatorController;
162
163     /**
164      * Overrides the BeanFactory.
165      */
166     @TestConfiguration
167     static class TestBeanFactory {
168
169         @Bean
170         A1ClientFactory getA1ClientFactory(@Autowired ApplicationConfig appConfig, @Autowired PolicyTypes types) {
171             return new MockA1ClientFactory(appConfig, types);
172         }
173
174         @Bean
175         public ServiceSupervision getServiceSupervision(@Autowired Services services,
176                 @Autowired A1ClientFactory a1ClientFactory, @Autowired Policies policies) {
177             Duration checkInterval = Duration.ofMillis(1);
178             return new ServiceSupervision(services, policies, a1ClientFactory, checkInterval);
179         }
180
181         @Bean
182         public ServletWebServerFactory servletContainer() {
183             return new TomcatServletWebServerFactory();
184         }
185     }
186
187     @LocalServerPort
188     private int port;
189
190     @BeforeEach
191     void init() {
192         this.applicationConfig.setAuthProviderUrl(baseUrl() + OpenPolicyAgentSimulatorController.ACCESS_CONTROL_URL);
193         rics.clear();
194         policies.clear();
195         policyTypes.clear();
196         services.clear();
197         a1ClientFactory.reset();
198     }
199
200     @AfterEach
201     void reset() {
202         rics.clear();
203         policies.clear();
204         policyTypes.clear();
205         services.clear();
206         a1ClientFactory.reset();
207         this.rAppSimulator.getTestResults().clear();
208         this.a1ClientFactory.setPolicyTypes(policyTypes); // Default same types in RIC and in this app
209         this.securityContext.setAuthTokenFilePath(null);
210         this.openPolicyAgentSimulatorController.getTestResults().reset();
211     }
212
213     @AfterAll
214     static void clearTestDir() {
215         try {
216             FileSystemUtils.deleteRecursively(Path.of("/tmp/pmstest"));
217         } catch (Exception e) {
218             logger.warn("Could test directory : {}", e.getMessage());
219         }
220     }
221
222     @AfterEach
223     void verifyNoRicLocks() {
224         for (Ric ric : this.rics.getRics()) {
225             Lock.Grant grant = ric.getLock().lockBlocking(LockType.EXCLUSIVE, "verifyNoRicLocks");
226             grant.unlockBlocking();
227             assertThat(ric.getLock().getLockCounter()).isZero();
228             assertThat(ric.getState()).isEqualTo(Ric.RicState.AVAILABLE);
229         }
230     }
231
232     @Test
233     @DisplayName("test ZZ Actuator")
234     void testZZActuator() {
235         // The test must be run last, hence the "ZZ" in the name. All succeeding tests
236         // will fail.
237         AsyncRestClient client = restClient(baseUrl(), false);
238
239         client.post("/actuator/loggers/org.onap.ccsdk.oran.a1policymanagementservice",
240                 "{\"configuredLevel\":\"trace\"}").block();
241
242         String resp = client.get("/actuator/loggers/org.onap.ccsdk.oran.a1policymanagementservice").block();
243         assertThat(resp).contains("TRACE");
244
245         client.post("/actuator/loggers/org.springframework.boot.actuate", "{\"configuredLevel\":\"trace\"}").block();
246
247         // This will stop the web server and all coming tests will fail.
248         ResponseEntity<String> entity = client.postForEntity("/actuator/shutdown", "").block();
249         assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
250         assertThat(((String) entity.getBody())).contains("Shutting down");
251     }
252
253     @Test
254     @DisplayName("test Persistency Policies")
255     void testPersistencyPolicies() throws Exception {
256         Ric ric = this.addRic("ric1");
257         PolicyType type = this.addPolicyType("type1", ric.id());
258
259         final int noOfPolicies = 100;
260         for (int i = 0; i < noOfPolicies; ++i) {
261             addPolicy("id" + i, type.getId(), "service", ric.id());
262         }
263         waitforS3();
264
265         {
266             Policies policiesLocal = new Policies(this.applicationConfig);
267             policiesLocal.restoreFromDatabase(ric, this.policyTypes).blockLast();
268             assertThat(policiesLocal.size()).isEqualTo(noOfPolicies);
269         }
270
271         {
272             restClient().delete("/policies/id2").block();
273             Policies policiesAfterDelete = new Policies(this.applicationConfig);
274             policiesAfterDelete.restoreFromDatabase(ric, this.policyTypes).blockLast();
275             assertThat(policiesAfterDelete.size()).isEqualTo(noOfPolicies - 1);
276         }
277     }
278
279     @Test
280     @DisplayName("test Persistency Policy Types")
281     void testPersistencyPolicyTypes() throws Exception {
282         Ric ric = this.addRic("ric1");
283         this.addPolicyType("type1", ric.id());
284         waitforS3();
285
286         PolicyTypes types = new PolicyTypes(this.applicationConfig);
287         types.restoreFromDatabase().blockLast();
288         assertThat(types.size()).isEqualTo(1);
289     }
290
291     @SuppressWarnings("squid:S2925") // "Thread.sleep" should not be used in tests.
292     private void waitforS3() throws Exception {
293         if (applicationConfig.isS3Enabled()) {
294             Thread.sleep(1000);
295         }
296     }
297
298     @Test
299     @DisplayName("test Persistency Service")
300     void testPersistencyService() throws Exception {
301         final String SERVICE = "serviceName";
302         putService(SERVICE, 1234, HttpStatus.CREATED);
303         assertThat(this.services.size()).isEqualTo(1);
304         Service service = this.services.getService(SERVICE);
305         waitforS3();
306
307         Services servicesRestored = new Services(this.applicationConfig);
308         servicesRestored.restoreFromDatabase().blockLast();
309         Service serviceRestored = servicesRestored.getService(SERVICE);
310         assertThat(servicesRestored.size()).isEqualTo(1);
311         assertThat(serviceRestored.getCallbackUrl()).isEqualTo(service.getCallbackUrl());
312         assertThat(serviceRestored.getKeepAliveInterval()).isEqualTo(service.getKeepAliveInterval());
313
314         // check that the service can be deleted
315         this.services.remove(SERVICE);
316         servicesRestored = new Services(this.applicationConfig);
317         assertThat(servicesRestored.size()).isZero();
318     }
319
320     @Test
321     @DisplayName("test Adding Ric From Configuration")
322     void testAddingRicFromConfiguration() throws Exception {
323         // Test adding the RIC from configuration
324
325         final String RIC = "ric1";
326         final String TYPE = "type123";
327         PolicyTypes nearRtRicPolicyTypes = new PolicyTypes(this.applicationConfig);
328         nearRtRicPolicyTypes.put(createPolicyType(TYPE));
329         this.a1ClientFactory.setPolicyTypes(nearRtRicPolicyTypes);
330
331         putService("service");
332
333         refreshConfigTask.handleUpdatedRicConfig( //
334                 new RicConfigUpdate(ricConfig(RIC, "me1"), RicConfigUpdate.Type.ADDED)) //
335                 .block();
336         waitForRicState(RIC, RicState.AVAILABLE);
337
338         // Test that the type has been synched
339         Ric addedRic = this.rics.getRic(RIC);
340         assertThat(addedRic.getSupportedPolicyTypes()).hasSize(1);
341         assertThat(addedRic.getSupportedPolicyTypes().iterator().next().getId()).isEqualTo(TYPE);
342
343         // Check that a service callback for the AVAILABLE RIC is invoked
344         final RappSimulatorController.TestResults receivedCallbacks = rAppSimulator.getTestResults();
345         await().untilAsserted(() -> assertThat(receivedCallbacks.getReceivedInfo()).hasSize(1));
346         ServiceCallbackInfo callbackInfo = receivedCallbacks.getReceivedInfo().get(0);
347         assertThat(callbackInfo.ricId).isEqualTo(RIC);
348         assertThat(callbackInfo.eventType).isEqualTo(ServiceCallbackInfo.EventType.AVAILABLE);
349     }
350
351     @Test
352     @DisplayName("test Adding Ric From Configuration non Responding Ric")
353     void testAddingRicFromConfiguration_nonRespondingRic() throws Exception {
354         putService("service");
355
356         final String RIC = "NonRespondingRic";
357         MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client(RIC);
358         doReturn(MockA1Client.monoError("error", HttpStatus.BAD_GATEWAY)).when(a1Client).getPolicyTypeIdentities();
359
360         refreshConfigTask.handleUpdatedRicConfig( //
361                 new RicConfigUpdate(ricConfig(RIC, "me1"), RicConfigUpdate.Type.ADDED)) //
362                 .block();
363
364         waitForRicState(RIC, RicState.UNAVAILABLE);
365
366         // Check that no service callback for the UNAVAILABLE RIC is invoked
367         final RappSimulatorController.TestResults receivedCallbacks = rAppSimulator.getTestResults();
368         await().untilAsserted(() -> assertThat(receivedCallbacks.getReceivedInfo()).isEmpty());
369
370         // Run a synch and check that the AVAILABLE notification is received
371         a1ClientFactory.reset();
372         supervision.checkAllRics();
373         waitForRicState(RIC, RicState.AVAILABLE);
374
375         await().untilAsserted(() -> assertThat(receivedCallbacks.getReceivedInfo()).hasSize(1));
376     }
377
378     @Test
379     @DisplayName("test Trust Validation")
380     void testTrustValidation() {
381         addRic("ric1");
382
383         String rsp = restClient(true).get("/rics").block(); // restClient(true) enables trust validation
384         assertThat(rsp).contains("ric1");
385
386     }
387
388     @Test
389     @DisplayName("test Get Rics")
390     void testGetRics() throws JsonProcessingException {
391         addRic("ric1");
392         this.addPolicyType("type1", "ric1");
393         String url = "/rics?policytype_id=type1";
394         String rsp = restClient().get(url).block();
395         String expectedResponse = "{\"rics\":[{\"managed_element_ids\":[],\"ric_id\":\"ric1\", \"state\":\"AVAILABLE\",\"policytype_ids\":[\"type1\"]}]}";
396         assertEquals(objectMapper.readTree(expectedResponse), objectMapper.readTree(rsp));
397
398         // nameless type for ORAN A1 1.1
399         addRic("ric2");
400         this.addPolicyType("", "ric2");
401         url = "/rics?policytype_id=";
402         rsp = restClient().get(url).block();
403         assertThat(rsp).contains("ric2") //
404                 .doesNotContain("ric1") //
405                 .contains("AVAILABLE");
406
407         // All RICs
408         rsp = restClient().get("/rics").block();
409         assertThat(rsp).contains("ric2") //
410                 .contains("ric1");
411
412         // Non existing policy type
413         url = "/rics?policytype_id=XXXX";
414         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
415     }
416
417     @Test
418     @DisplayName("test Synchronization")
419     void testSynchronization() throws Exception {
420         // Two polictypes will be put in the NearRT RICs
421         PolicyTypes nearRtRicPolicyTypes = new PolicyTypes(this.applicationConfig);
422         nearRtRicPolicyTypes.put(createPolicyType("typeName"));
423         nearRtRicPolicyTypes.put(createPolicyType("typeName2"));
424         this.a1ClientFactory.setPolicyTypes(nearRtRicPolicyTypes);
425
426         // One type and one instance added to the Policy Management Service's storage
427         final String ric1Name = "ric1";
428         Ric ric1 = addRic(ric1Name);
429         Policy policy2 = addPolicy("policyId2", "typeName", "service", ric1Name);
430         Ric ric2 = addRic("ric2");
431
432         getA1Client(ric1Name).putPolicy(policy2); // put it in the RIC (Near-RT RIC)
433         policies.remove(policy2); // Remove it from the repo -> should be deleted in the RIC
434
435         String policyId = "policyId";
436         Policy policy = addPolicy(policyId, "typeName", "service", ric1Name); // This should be created in the RIC
437         supervision.checkAllRics(); // The created policy should be put in the RIC
438
439         // Wait until synch is completed
440         waitForRicState(ric1Name, RicState.SYNCHRONIZING);
441         waitForRicState(ric1Name, RicState.AVAILABLE);
442         waitForRicState("ric2", RicState.AVAILABLE);
443
444         Policies ricPolicies = getA1Client(ric1Name).getPolicies();
445         assertThat(ricPolicies.size()).isEqualTo(1);
446         Policy ricPolicy = ricPolicies.get(policyId);
447         assertThat(ricPolicy.getJson()).isEqualTo(policy.getJson());
448
449         // Both types should be in the Policy Management Service's storage after the
450         // synch
451         assertThat(ric1.getSupportedPolicyTypes()).hasSize(2);
452         assertThat(ric2.getSupportedPolicyTypes()).hasSize(2);
453     }
454
455     @Test
456     @DisplayName("test Get Ric")
457     void testGetRic() throws Exception {
458         String ricId = "ric1";
459         String managedElementId = "kista_1";
460         addRic(ricId, managedElementId);
461
462         String url = "/rics/ric?managed_element_id=" + managedElementId;
463         String rsp = restClient().get(url).block();
464         RicInfo ricInfo = objectMapper.readValue(rsp, RicInfo.class);
465         assertThat(ricInfo.getRicId()).isEqualTo(ricId);
466
467         url = "/rics/ric?ric_id=" + ricId;
468         rsp = restClient().get(url).block();
469         ricInfo = objectMapper.readValue(rsp, RicInfo.class);
470         assertThat(ricInfo.getRicId()).isEqualTo(ricId);
471
472         // test GET RIC for ManagedElement that does not exist
473         url = "/rics/ric?managed_element_id=" + "junk";
474         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
475
476         url = "/rics/ric";
477         testErrorCode(restClient().get(url), HttpStatus.BAD_REQUEST);
478     }
479
480     private String putPolicyBody(String serviceName, String ricId, String policyTypeName, String policyInstanceId,
481             boolean isTransient, String statusNotificationUri) throws JsonProcessingException {
482         PolicyInfo policyInfo = new PolicyInfo(ricId, policyInstanceId, jsonString(), policyTypeName);
483         policyInfo.setServiceId(serviceName);
484         policyInfo.setTransient(isTransient);
485         policyInfo.setStatusNotificationUri(statusNotificationUri);
486         return objectMapper.writeValueAsString(policyInfo);
487     }
488
489     private String putPolicyBody(String serviceName, String ricId, String policyTypeName, String policyInstanceId) throws JsonProcessingException {
490         return putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId, false, "statusUri");
491     }
492
493     @Test
494     @DisplayName("test Put Policy")
495     void testPutPolicy() throws Exception {
496         String serviceName = "service.1";
497         String ricId = "ric.1";
498         String policyTypeName = "type1_1.2.3";
499         String policyInstanceId = "instance_1.2.3";
500
501         putService(serviceName);
502         addPolicyType(policyTypeName, ricId);
503
504         // PUT a transient policy
505         String url = "/policies";
506         String policyBody = putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId, true, "statusNotif");
507         this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE);
508
509         restClient().put(url, policyBody).block();
510         {
511             // Check the authorization request
512             OpenPolicyAgentSimulatorController.TestResults res =
513                     this.openPolicyAgentSimulatorController.getTestResults();
514             assertThat(res.receivedRequests).hasSize(1);
515             PolicyAuthorizationRequest req = res.receivedRequests.get(0);
516             assertThat(req.getInput().getAccessType()).isEqualTo(AccessType.WRITE);
517             assertThat(req.getInput().getPolicyTypeId()).isEqualTo(policyTypeName);
518         }
519
520         Policy policy = policies.getPolicy(policyInstanceId);
521         assertThat(policy).isNotNull();
522         assertThat(policy.getId()).isEqualTo(policyInstanceId);
523         assertThat(policy.getOwnerServiceId()).isEqualTo(serviceName);
524         assertThat(policy.getRic().id()).isEqualTo(ricId);
525         assertThat(policy.isTransient()).isTrue();
526
527         // Put a non transient policy
528         policyBody = putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId);
529         restClient().put(url, policyBody).block();
530         policy = policies.getPolicy(policyInstanceId);
531         assertThat(policy.isTransient()).isFalse();
532
533         url = "/policy-instances";
534         String rsp = restClient().get(url).block();
535         assertThat(rsp).as("Response contains policy instance ID.").contains(policyInstanceId);
536
537         url = "/policies/" + policyInstanceId;
538         rsp = restClient().get(url).block();
539
540         assertThat(rsp).contains(policyBody);
541
542         // Test of error codes
543         url = "/policies";
544         policyBody = putPolicyBody(serviceName, ricId + "XX", policyTypeName, policyInstanceId);
545         testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND);
546
547         policyBody = putPolicyBody(serviceName, ricId, policyTypeName + "XX", policyInstanceId);
548         addPolicyType(policyTypeName + "XX", "otherRic");
549         testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND);
550
551         policyBody = putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId);
552         this.rics.getRic(ricId).setState(Ric.RicState.SYNCHRONIZING);
553         testErrorCode(restClient().put(url, policyBody), HttpStatus.LOCKED);
554         this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE);
555     }
556
557     @Test
558     void testFineGrainedAuth() throws Exception {
559         final String POLICY_ID = "policyId";
560         final String RIC_ID = "ric1";
561         final String TYPE_ID = "typeName";
562         addPolicy(POLICY_ID, TYPE_ID, null, RIC_ID);
563         assertThat(policies.size()).isEqualTo(1);
564
565         this.applicationConfig
566                 .setAuthProviderUrl(baseUrl() + OpenPolicyAgentSimulatorController.ACCESS_CONTROL_URL_REJECT);
567         String url = "/policy-instances";
568         String rsp = restClient().get(url).block();
569         assertThat(rsp).as("Response contains no policy instance ID.").contains("[]");
570
571         url = "/policies/" + POLICY_ID;
572         testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized");
573
574         url = "/policies";
575         String policyBody = putPolicyBody(null, RIC_ID, TYPE_ID, POLICY_ID, false, null);
576         testErrorCode(restClient().put(url, policyBody), HttpStatus.UNAUTHORIZED, "Not authorized");
577
578         rsp = restClient().get(url).block();
579         assertThat(rsp).as("Response contains no policy instance ID.").contains("[]");
580     }
581
582     @Test
583     void testFineGrainedAuth_OPA_UNAVALIABLE() throws Exception {
584         final String POLICY_ID = "policyId";
585         final String RIC_ID = "ric1";
586         final String TYPE_ID = "typeName";
587         addPolicy(POLICY_ID, TYPE_ID, null, RIC_ID);
588         assertThat(policies.size()).isEqualTo(1);
589
590         this.applicationConfig.setAuthProviderUrl("junk");
591
592         String url = "/policy-instances";
593         String rsp = restClient().get(url).block();
594         assertThat(rsp).as("Response contains no policy instance ID.").contains("[]");
595
596         url = "/policies/" + POLICY_ID;
597         testErrorCode(restClient().delete(url), HttpStatus.UNAUTHORIZED, "Not authorized");
598
599         url = "/policies";
600         String policyBody = putPolicyBody(null, RIC_ID, TYPE_ID, POLICY_ID, false, null);
601         testErrorCode(restClient().put(url, policyBody), HttpStatus.UNAUTHORIZED, "Not authorized");
602
603         rsp = restClient().get(url).block();
604         assertThat(rsp).as("Response contains no policy instance ID.").contains("[]");
605     }
606     @Test
607     @DisplayName("test Put Policy No Service No Status Uri")
608     void testPutPolicy_NoServiceNoStatusUri() throws Exception {
609         String ricId = "ric.1";
610         String policyTypeName = "type1_1.2.3";
611         String policyInstanceId = "instance_1.2.3";
612
613         addPolicyType(policyTypeName, ricId);
614
615         // PUT a transient policy
616         String url = "/policies";
617         String policyBody = putPolicyBody(null, ricId, policyTypeName, policyInstanceId, true, null);
618         this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE);
619
620         restClient().put(url, policyBody).block();
621
622         Policy policy = policies.getPolicy(policyInstanceId);
623         assertThat(policy).isNotNull();
624         assertThat(policy.getOwnerServiceId()).isBlank();
625         assertThat(policy.getStatusNotificationUri()).isBlank();
626     }
627
628     @Test
629     /**
630      * Test that HttpStatus and body from failing REST call to A1 is passed on to
631      * the caller.
632      *
633      * @throws ServiceException
634      */
635     @DisplayName("test Error From Ric")
636     void testErrorFromRic() throws ServiceException, JsonProcessingException {
637         putService("service1");
638         addPolicyType("type1", "ric1");
639
640         MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client("ric1");
641         HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
642         String responseBody = "Refused";
643         byte[] responseBodyBytes = responseBody.getBytes(StandardCharsets.UTF_8);
644
645         WebClientResponseException a1Exception = new WebClientResponseException(httpStatus.value(), "statusText", null,
646                 responseBodyBytes, StandardCharsets.UTF_8, null);
647         doReturn(Mono.error(a1Exception)).when(a1Client).putPolicy(any());
648
649         // PUT Policy
650         String putBody = putPolicyBody("service1", "ric1", "type1", "id1");
651         String url = "/policies";
652         testErrorCode(restClient().put(url, putBody), httpStatus, responseBody);
653
654         // DELETE POLICY
655         this.addPolicy("instance1", "type1", "service1", "ric1");
656         doReturn(Mono.error(a1Exception)).when(a1Client).deletePolicy(any());
657         testErrorCode(restClient().delete("/policies/instance1"), httpStatus, responseBody);
658
659     }
660
661     @Test
662     @DisplayName("test Put Typeless Policy")
663     void testPutTypelessPolicy() throws Exception {
664         putService("service1");
665         addPolicyType("", "ric1");
666         String body = putPolicyBody("service1", "ric1", "", "id1");
667         restClient().put("/policies", body).block();
668
669         String rsp = restClient().get("/policy-instances").block();
670         PolicyInfoList info = objectMapper.readValue(rsp, PolicyInfoList.class);
671         assertThat(info.getPolicies()).hasSize(1);
672         PolicyInfo policyInfo = info.getPolicies().iterator().next();
673         assertThat(policyInfo.getPolicyId()).isEqualTo("id1");
674         assertThat(policyInfo.getPolicytypeId()).isEmpty();
675     }
676
677     @Test
678     @DisplayName("test Update Service")
679     void testUpdateService() throws Exception {
680         this.addRic("ric1");
681         this.addPolicy("policyId", "type1", "", "ric1");
682
683         String url = "/policies?service_id=";
684         String resp = restClient().get(url).block();
685         String expectedResponse = "{\"policy_ids\":[\"policyId\"]}";
686         assertEquals(expectedResponse, resp);
687
688         this.addPolicy("policyId", "type1", "service", "ric1");
689         url = "/policies?service_id=";
690         resp = restClient().get(url).block();
691         expectedResponse = "{\"policy_ids\":[]}";
692         assertEquals(expectedResponse, resp);
693
694         url = "/policies?service_id=service";
695         resp = restClient().get(url).block();
696         assertThat(resp).contains("[\"policyId\"]");
697     }
698
699     @Test
700     @DisplayName("test Refuse To Update Policy")
701     void testRefuseToUpdatePolicy() throws Exception {
702         // Test that only the json can be changed for a already created policy
703         // In this case service is attempted to be changed
704         this.addRic("ric1");
705         this.addRic("ricXXX");
706         this.addPolicy("instance1", "type1", "service1", "ric1");
707         this.addPolicy("instance2", "type1", "service1", "ricXXX");
708
709         // Try change ric1 -> ricXXX
710         String bodyWrongRic = putPolicyBody("service1", "ricXXX", "type1", "instance1");
711         testErrorCode(restClient().put("/policies", bodyWrongRic), HttpStatus.CONFLICT);
712     }
713
714     @Test
715     @DisplayName("test Get Policy")
716     void testGetPolicy() throws Exception {
717         String url = "/policies/id";
718         Policy policy = addPolicy("id", "typeName", "service1", "ric1");
719         {
720             String response = restClient().get(url).block();
721             String expectedResponse = "{\"ric_id\":\"ric1\",\"service_id\":\"service1\",\"policy_id\":\"id\",\"policy_data\":{\"servingCellNrcgi\":\"1\"},\"status_notification_uri\":\"/policy-status?id=XXX\",\"policytype_id\":\"typeName\",\"transient\":false}";
722             assertEquals(objectMapper.readTree(expectedResponse), objectMapper.readTree(response));
723         }
724         {
725             policies.remove(policy);
726             testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
727         }
728     }
729
730     @Test
731     @DisplayName("test Delete Policy")
732     void testDeletePolicy() throws Exception {
733         String policyId = "id.1";
734         addPolicy(policyId, "typeName", "service1", "ric1");
735         assertThat(policies.size()).isEqualTo(1);
736
737         String url = "/policies/" + policyId;
738         ResponseEntity<String> entity = restClient().deleteForEntity(url).block();
739
740         assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
741         assertThat(policies.size()).isZero();
742
743         // Delete a non existing policy
744         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
745     }
746
747
748     @Test
749     @DisplayName("test Get Policy Type")
750     void testGetPolicyType() throws Exception {
751         String typeId = "AC.D";
752         addPolicyType(typeId, "ric1");
753
754         waitForRicState("ric1", RicState.AVAILABLE);
755
756         String url = "/policy-types/" + typeId;
757
758         String response = this.restClient().get(url).block();
759
760         assertEquals("{\"policy_schema\":{\"title\":\"AC.D\"}}", response);
761
762         // Get non existing schema
763         url = "/policy-types/JUNK";
764         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
765     }
766
767     String createPolicyTypesJson(String... types) throws JsonProcessingException {
768         List<String> list = new ArrayList<>();
769         Collections.addAll(list, types);
770         PolicyTypeIdList ids = new PolicyTypeIdList();
771         ids.setPolicytypeIds(list);
772         return objectMapper.writeValueAsString(ids);
773     }
774
775     @Test
776     @DisplayName("test Get Policy Types")
777     void testGetPolicyTypes() throws JsonProcessingException {
778         String TYPE_ID_1 = "A_type1_1.9.0";
779         String TYPE_ID_2 = "A_type1_2.0.0";
780         String TYPE_ID_3 = "A_type1_1.5.0";
781         String TYPE_ID_4 = "type3_1.9.0";
782         addPolicyType(TYPE_ID_1, "ric1");
783         addPolicyType(TYPE_ID_2, "ric2");
784         addPolicyType(TYPE_ID_3, "ric2");
785         addPolicyType(TYPE_ID_4, "ric2");
786
787         addPolicyType("junk", "ric2");
788         addPolicyType("junk_a.b.c", "ric2");
789
790         String url = "/policy-types";
791         String rsp = restClient().get(url).block();
792         assertThat(rsp).contains(TYPE_ID_1, TYPE_ID_2);
793
794         url = "/policy-types?ric_id=ric1";
795         rsp = restClient().get(url).block();
796         String expResp = createPolicyTypesJson(TYPE_ID_1);
797         assertThat(rsp).isEqualTo(expResp);
798
799         // Get policy types for non existing RIC
800         url = "/policy-types?ric_id=ric1XXX";
801         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
802
803         // All types with a type_name
804         url = "/policy-types?type_name=A_type1";
805         rsp = restClient().get(url).block();
806         assertThat(rsp).contains(TYPE_ID_1, TYPE_ID_2);
807
808         // All types compatible with type1_1.5.0 (which is type1_1.9.0)
809         url = "/policy-types?type_name=A_type1&&compatible_with_version=1.5.0";
810         rsp = restClient().get(url).block();
811         expResp = createPolicyTypesJson(TYPE_ID_3, TYPE_ID_1);
812         assertThat(rsp).isEqualTo(expResp);
813
814         url = "/policy-types?type_name=A_type1&&compatible_with_version=junk";
815         testErrorCode(restClient().get(url), HttpStatus.BAD_REQUEST, "Version must contain major.minor.patch code");
816
817         url = "/policy-types?type_name=A_type1&&compatible_with_version=a.b.c";
818         testErrorCode(restClient().get(url), HttpStatus.BAD_REQUEST, "Syntax error in");
819
820         url = "/policy-types?compatible_with_version=1.5.0";
821         testErrorCode(restClient().get(url), HttpStatus.BAD_REQUEST, "type_name");
822     }
823
824     @Test
825     @DisplayName("test Get Policy Instances")
826     void testGetPolicyInstances() throws Exception {
827         addPolicy("id1", "type1", "service1");
828
829         String url = "/policy-instances";
830         String response = restClient().get(url).block();
831         logger.info(response);
832         PolicyInfoList policyInfoList = objectMapper.readValue(response, PolicyInfoList.class);
833         assertThat(policyInfoList.getPolicies()).hasSize(1);
834         PolicyInfo policyInfo = policyInfoList.getPolicies().iterator().next();
835         assertThat(policyInfo.getPolicyId()).isEqualTo("id1");
836         assertThat(policyInfo.getPolicytypeId()).isEqualTo("type1");
837         assertThat(policyInfo.getServiceId()).isEqualTo("service1");
838     }
839
840     @Test
841     @DisplayName("test Get Policy Instances Filter")
842     void testGetPolicyInstancesFilter() throws Exception {
843         addPolicy("id1", "type1", "service1");
844         addPolicy("id2", "type1", "service2");
845         addPolicy("id3", "type2", "service1");
846         addPolicy("id4", "type1_1.0.0", "service1");
847
848         String url = "/policy-instances?policytype_id=type1";
849         String rsp = restClient().get(url).block();
850         logger.info(rsp);
851         assertThat(rsp).contains("id1")
852                 .contains("id2")
853                 .doesNotContain("id3");
854
855         url = "/policy-instances?policytype_id=type1&service_id=service2";
856         rsp = restClient().get(url).block();
857         logger.info(rsp);
858         assertThat(rsp).doesNotContain("id1")
859                 .contains("id2") //
860                 .doesNotContain("id3");
861
862         url = "/policy-instances?type_name=type1";
863         rsp = restClient().get(url).block();
864         assertThat(rsp).contains("id1") //
865                 .contains("id2") //
866                 .doesNotContain("id3")
867                 .contains("id4");
868
869         // Test get policies for non existing type
870         url = "/policy-instances?policytype_id=type1XXX";
871         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
872
873         // Test get policies for non existing RIC
874         url = "/policy-instances?ric_id=XXX";
875         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
876     }
877
878     @Test
879     @DisplayName("test Get Policy Ids Filter")
880     void testGetPolicyIdsFilter() throws Exception {
881         addPolicy("id1", "type1", "service1", "ric1");
882         addPolicy("id2", "type1", "service2", "ric1");
883         addPolicy("id3", "type2", "service1", "ric1");
884         addPolicy("id4", "type1_1.0.0", "service1");
885
886         String url = "/policies?policytype_id=type1";
887         String rsp = restClient().get(url).block();
888         logger.info(rsp);
889         assertThat(rsp).contains("id1")
890                 .contains("id2")
891                 .doesNotContain("id3");
892
893         url = "/policies?policytype_id=type1&service_id=service1&ric=ric1";
894         rsp = restClient().get(url).block();
895         PolicyIdList respList = objectMapper.readValue(rsp, PolicyIdList.class);
896         assertThat(respList.getPolicyIds().iterator().next()).isEqualTo("id1");
897
898         url = "/policies?type_name=type1&service_id=service1";
899         rsp = restClient().get(url).block();
900         assertThat(rsp).contains("id1").contains("id4");
901         assertThat(objectMapper.readValue(rsp, PolicyIdList.class).getPolicyIds()).hasSize(2);
902
903         // Test get policy ids for non existing type
904         url = "/policies?policytype_id=type1XXX";
905         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
906
907         // Test get policy ids for non existing RIC
908         url = "/policies?ric_id=XXX";
909         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
910     }
911
912
913     @Test
914     @DisplayName("test Put And Get Service")
915     void testPutAndGetService() throws Exception {
916         // PUT
917         String serviceName = "ac.dc";
918         putService(serviceName, 0, HttpStatus.CREATED);
919         putService(serviceName, 0, HttpStatus.OK);
920
921         // GET one service
922         String url = "/services?service_id=" + serviceName;
923         String rsp = restClient().get(url).block();
924         ServiceStatusList info = objectMapper.readValue(rsp, ServiceStatusList.class);
925         assertThat(info.getServiceList()).hasSize(1);
926         ServiceStatus status = info.getServiceList().iterator().next();
927         assertThat(status.getKeepAliveIntervalSeconds()).isZero();
928         assertThat(status.getServiceId()).isEqualTo(serviceName);
929
930         // GET (all)
931         url = "/services";
932         rsp = restClient().get(url).block();
933         assertThat(rsp).as("Response contains service name").contains(serviceName);
934         logger.info(rsp);
935
936         // Keep alive
937         url = "/services/" + serviceName + "/keepalive";
938         ResponseEntity<?> entity = restClient().putForEntity(url).block();
939         assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
940
941         // DELETE service
942         addPolicy("id1", "type1", serviceName);
943         assertThat(services.size()).isEqualTo(1);
944         url = "/services/" + serviceName;
945         restClient().delete(url).block();
946         assertThat(services.size()).isZero();
947
948         // Keep alive, no registered service
949         testErrorCode(restClient().put("/services/junk/keepalive", ""), HttpStatus.NOT_FOUND);
950
951         // PUT service with bad payload
952         testErrorCode(restClient().put("/services", "crap"), HttpStatus.BAD_REQUEST, false);
953         testErrorCode(restClient().put("/services", "{}"), HttpStatus.BAD_REQUEST, false);
954         testErrorCode(restClient().put("/services", createServiceJson(serviceName, -123)), HttpStatus.BAD_REQUEST,
955                 false);
956         testErrorCode(restClient().put("/services", createServiceJson(serviceName, 0, "missing.portandprotocol.com")),
957                 HttpStatus.BAD_REQUEST, false);
958
959         // GET non existing service
960         testErrorCode(restClient().get("/services?service_id=XXX"), HttpStatus.NOT_FOUND);
961     }
962
963     @Test
964     @DisplayName("test delete Service with no authorization")
965     void testDeleteServiceWithNoAuth() throws Exception {
966         // PUT service
967         String serviceName = "ac.dc";
968         putService(serviceName, 0, HttpStatus.CREATED);
969
970         // No Authorization to Delete
971         this.applicationConfig
972                 .setAuthProviderUrl(baseUrl() + OpenPolicyAgentSimulatorController.ACCESS_CONTROL_URL_REJECT);
973         addPolicy("id1", "type1", serviceName);
974         assertThat(services.size()).isEqualTo(1);
975         String url = "/services/" + serviceName;
976         restClient().delete(url).block();
977         assertThat(services.size()).isZero();
978         assertThat(policies.size()).isEqualTo(1);
979         testErrorCode(restClient().get("/policies/id1"), HttpStatus.UNAUTHORIZED);
980     }
981
982     @Test
983     @DisplayName("test delete Service with no service")
984     void testDeleteServiceWithNoService() {
985         String url = "/services/" + "NoService";
986         testErrorCode(restClient().delete(url), HttpStatus.NOT_FOUND);
987     }
988
989     @Test
990     @DisplayName("test Service Supervision")
991     void testServiceSupervision() throws JsonProcessingException {
992         putService("service1", 2, HttpStatus.CREATED);
993         addPolicyType("type1", "ric1");
994
995         String policyBody = putPolicyBody("service1", "ric1", "type1", "instance1");
996         restClient().put("/policies", policyBody).block();
997
998         assertThat(policies.size()).isEqualTo(1);
999         assertThat(services.size()).isEqualTo(1);
1000
1001         // Timeout after ~2 second
1002         await().untilAsserted(() -> assertThat(policies.size()).isZero());
1003         assertThat(services.size()).isZero();
1004     }
1005
1006     @Test
1007     @DisplayName("test Get Policy Status")
1008     void testGetPolicyStatus() throws Exception {
1009         addPolicy("id", "typeName", "service1", "ric1");
1010         assertThat(policies.size()).isEqualTo(1);
1011
1012         String url = "/policies/id/status";
1013         String response = restClient().get(url).block();
1014         PolicyStatusInfo info = objectMapper.readValue(response, PolicyStatusInfo.class);
1015         assertThat(info.getStatus()).isEqualTo("OK");
1016
1017         // GET non existing policy status
1018         url = "/policies/XXX/status";
1019         testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
1020
1021         // GET STATUS, the NearRT RIC returns error
1022         MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client("ric1");
1023         url = "/policies/id/status";
1024         WebClientResponseException a1Exception = new WebClientResponseException(404, "", null, null, null);
1025         doReturn(Mono.error(a1Exception)).when(a1Client).getPolicyStatus(any());
1026         response = restClient().get(url).block();
1027         info = objectMapper.readValue(response, PolicyStatusInfo.class);
1028         assertThat(info.getStatus()).hasToString("{}");
1029     }
1030
1031     @Test
1032     @DisplayName("test Get Service Status")
1033     void testGetServiceStatus() {
1034         String url = "/status";
1035         String rsp = restClient().get(url).block();
1036         assertThat(rsp).contains("success");
1037
1038         rsp = restClient(baseUrl(), false).get(url).block(); // V1 status is used by a readinessProbe
1039         assertThat(rsp).isEqualTo("success");
1040     }
1041
1042     @Test
1043     @DisplayName("test Service Notification")
1044     void testServiceNotification() throws Exception {
1045
1046         final String AUTH_TOKEN = "testToken";
1047         Path authFile = Files.createTempFile("pmsTestAuthToken", ".txt");
1048         Files.write(authFile, AUTH_TOKEN.getBytes());
1049         this.securityContext.setAuthTokenFilePath(authFile);
1050
1051         putService("junkService");
1052         Service junkService = this.services.get("junkService");
1053         junkService.setCallbackUrl("https://junk");
1054         putService("service");
1055
1056         Ric ric = addRic("ric1");
1057         ric.setState(Ric.RicState.UNAVAILABLE);
1058         supervision.checkAllRics();
1059         waitForRicState("ric1", RicState.AVAILABLE);
1060
1061         final RappSimulatorController.TestResults receivedCallbacks = rAppSimulator.getTestResults();
1062         await().untilAsserted(() -> assertThat(receivedCallbacks.getReceivedInfo()).hasSize(1));
1063         ServiceCallbackInfo callbackInfo = receivedCallbacks.getReceivedInfo().get(0);
1064         assertThat(callbackInfo.ricId).isEqualTo("ric1");
1065         assertThat(callbackInfo.eventType).isEqualTo(ServiceCallbackInfo.EventType.AVAILABLE);
1066
1067         var headers = receivedCallbacks.receivedHeaders.get(0);
1068         assertThat(headers).containsEntry("authorization", "Bearer " + AUTH_TOKEN);
1069
1070         Files.delete(authFile);
1071     }
1072
1073     private Policy addPolicy(String id, String typeName, String service, String ric) throws ServiceException {
1074        try {
1075            addRic(ric);
1076            Policy policy = Policy.builder()
1077                    .id(id)
1078                    .json(objectMapper.writeValueAsString(jsonString()))
1079                    .ownerServiceId(service)
1080                    .ric(rics.getRic(ric))
1081                    .type(addPolicyType(typeName, ric))
1082                    .lastModified(Instant.now())
1083                    .isTransient(false)
1084                    .statusNotificationUri("/policy-status?id=XXX")
1085                    .build();
1086            policies.put(policy);
1087            return policy;
1088        } catch (JsonProcessingException ex) {
1089             throw new RuntimeException(ex);
1090        }
1091     }
1092
1093     private Policy addPolicy(String id, String typeName, String service) throws ServiceException {
1094         return addPolicy(id, typeName, service, "ric");
1095     }
1096
1097     private String createServiceJson(String name, long keepAliveIntervalSeconds) throws JsonProcessingException {
1098         String callbackUrl = baseUrl() + RappSimulatorController.SERVICE_CALLBACK_URL;
1099         return createServiceJson(name, keepAliveIntervalSeconds, callbackUrl);
1100     }
1101
1102     private String createServiceJson(String name, long keepAliveIntervalSeconds, String url) throws JsonProcessingException {
1103         ServiceRegistrationInfo service = new ServiceRegistrationInfo(name)
1104                 .keepAliveIntervalSeconds(keepAliveIntervalSeconds)
1105                 .callbackUrl(url);
1106
1107         return objectMapper.writeValueAsString(service);
1108     }
1109
1110     private void putService(String name) throws JsonProcessingException {
1111         putService(name, 0, null);
1112     }
1113
1114     private void putService(String name, long keepAliveIntervalSeconds, @Nullable HttpStatus expectedStatus) throws JsonProcessingException {
1115         String url = "/services";
1116         String body = createServiceJson(name, keepAliveIntervalSeconds);
1117         ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
1118         if (expectedStatus != null) {
1119             assertNotNull(resp);
1120             assertEquals(expectedStatus, resp.getStatusCode(), "");
1121         }
1122     }
1123
1124     private Map<String,String> jsonString() {
1125         Map<String,String> policyDataInMap = new HashMap<>();
1126         policyDataInMap.put("servingCellNrcgi","1");
1127         return policyDataInMap;
1128     }
1129
1130     @Test
1131     @DisplayName("test Concurrency")
1132     void testConcurrency() throws Exception {
1133         this.applicationConfig.setAuthProviderUrl("");
1134         logger.info("Concurrency test starting");
1135         final Instant startTime = Instant.now();
1136         List<Thread> threads = new ArrayList<>();
1137         List<ConcurrencyTestRunnable> tests = new ArrayList<>();
1138         a1ClientFactory.setResponseDelay(Duration.ofMillis(2));
1139         addRic("ric");
1140         addPolicyType("type1", "ric");
1141         addPolicyType("type2", "ric");
1142
1143         final String NON_RESPONDING_RIC = "NonRespondingRic";
1144         Ric nonRespondingRic = addRic(NON_RESPONDING_RIC);
1145         MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client(NON_RESPONDING_RIC);
1146         a1Client.setErrorInject("errorInject");
1147
1148         for (int i = 0; i < 10; ++i) {
1149             AsyncRestClient restClient = restClient();
1150             ConcurrencyTestRunnable test =
1151                     new ConcurrencyTestRunnable(restClient, supervision, a1ClientFactory, rics, policyTypes);
1152             Thread thread = new Thread(test, "TestThread_" + i);
1153             thread.start();
1154             threads.add(thread);
1155             tests.add(test);
1156         }
1157         for (Thread t : threads) {
1158             t.join();
1159         }
1160         for (ConcurrencyTestRunnable test : tests) {
1161             assertThat(test.isFailed()).isFalse();
1162         }
1163         assertThat(policies.size()).isZero();
1164         logger.info("Concurrency test took: {}", Duration.between(startTime, Instant.now()));
1165
1166         assertThat(nonRespondingRic.getState()).isEqualTo(RicState.UNAVAILABLE);
1167         nonRespondingRic.setState(RicState.AVAILABLE);
1168     }
1169
1170     private AsyncRestClient restClient(String baseUrl, boolean useTrustValidation) {
1171         WebClientConfig config = this.applicationConfig.getWebClientConfig();
1172         config = WebClientConfig.builder()
1173                 .keyStoreType(config.getKeyStoreType())
1174                 .keyStorePassword(config.getKeyStorePassword())
1175                 .keyStore(config.getKeyStore())
1176                 .keyPassword(config.getKeyPassword())
1177                 .isTrustStoreUsed(useTrustValidation)
1178                 .trustStore(config.getTrustStore())
1179                 .trustStorePassword(config.getTrustStorePassword())
1180                 .httpProxyConfig(config.getHttpProxyConfig())
1181                 .build();
1182
1183         AsyncRestClientFactory f = new AsyncRestClientFactory(config, new SecurityContext(""));
1184         return f.createRestClientNoHttpProxy(baseUrl);
1185
1186     }
1187
1188     private String baseUrl() {
1189         return "https://localhost:" + port;
1190     }
1191
1192     private AsyncRestClient restClient(boolean useTrustValidation) {
1193         return restClient(baseUrl() + Consts.V2_API_ROOT, useTrustValidation);
1194     }
1195
1196     private AsyncRestClient restClient() {
1197         return restClient(false);
1198     }
1199
1200     private void testErrorCode(Mono<?> request, HttpStatus expStatus) {
1201         testErrorCode(request, expStatus, "", true);
1202     }
1203
1204     private void testErrorCode(Mono<?> request, HttpStatus expStatus, boolean expectApplicationProblemJsonMediaType) {
1205         testErrorCode(request, expStatus, "", expectApplicationProblemJsonMediaType);
1206     }
1207
1208     private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) {
1209         testErrorCode(request, expStatus, responseContains, true);
1210     }
1211
1212     private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains,
1213             boolean expectApplicationProblemJsonMediaType) {
1214         StepVerifier.create(request)
1215                 .expectSubscription()
1216                 .expectErrorMatches(
1217                         t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType))
1218                 .verify();
1219     }
1220
1221     private void waitForRicState(String ricId, RicState state) throws ServiceException {
1222         Ric ric = rics.getRic(ricId);
1223         await().untilAsserted(() -> state.equals(ric.getState()));
1224     }
1225
1226     private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains,
1227             boolean expectApplicationProblemJsonMediaType) {
1228         assertTrue(throwable instanceof WebClientResponseException);
1229         WebClientResponseException responseException = (WebClientResponseException) throwable;
1230         String body = responseException.getResponseBodyAsString();
1231         assertThat(body).contains(responseContains);
1232         assertThat(responseException.getStatusCode()).isEqualTo(expStatus);
1233
1234         if (expectApplicationProblemJsonMediaType) {
1235             assertThat(responseException.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON);
1236         }
1237         return true;
1238     }
1239
1240     private MockA1Client getA1Client(String ricId) {
1241         return a1ClientFactory.getOrCreateA1Client(ricId);
1242     }
1243
1244     private PolicyType createPolicyType(String policyTypeName) {
1245         return PolicyType.builder()
1246                 .id(policyTypeName)
1247                 .schema("{\"title\":\"" + policyTypeName + "\"}")
1248                 .build();
1249     }
1250
1251     private PolicyType addPolicyType(String policyTypeName, String ricId) {
1252         PolicyType type = createPolicyType(policyTypeName);
1253         policyTypes.put(type);
1254         addRic(ricId).addSupportedPolicyType(type);
1255         return type;
1256     }
1257
1258     private Ric addRic(String ricId) {
1259         return addRic(ricId, null);
1260     }
1261
1262     private RicConfig ricConfig(String ricId, String managedElement) {
1263         List<String> mes = new ArrayList<>();
1264         if (managedElement != null) {
1265             mes.add(managedElement);
1266         }
1267         return RicConfig.builder()
1268                 .ricId(ricId)
1269                 .baseUrl(ricId)
1270                 .managedElementIds(mes)
1271                 .build();
1272     }
1273
1274     private Ric addRic(String ricId, String managedElement) {
1275         if (rics.get(ricId) != null) {
1276             return rics.get(ricId);
1277         }
1278
1279         RicConfig conf = ricConfig(ricId, managedElement);
1280         Ric ric = new Ric(conf);
1281         ric.setState(Ric.RicState.AVAILABLE);
1282         this.rics.put(ric);
1283         return ric;
1284     }
1285
1286 }