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