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