9a95590e19d72a7cab9056230581f26e288cc37b
[policy/pap.git] / main / src / test / java / org / onap / policy / pap / main / rest / TestProviderBase.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP PAP
4  * ================================================================================
5  * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2021, 2023 Nordix Foundation.
7  * Modifications Copyright (C) 2021-2022 Bell Canada. All rights reserved.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.pap.main.rest;
24
25 import static org.assertj.core.api.Assertions.assertThatThrownBy;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertSame;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33
34 import jakarta.ws.rs.core.Response.Status;
35 import java.util.Collections;
36 import java.util.LinkedList;
37 import java.util.List;
38 import java.util.Queue;
39 import org.junit.jupiter.api.AfterAll;
40 import org.junit.jupiter.api.BeforeEach;
41 import org.junit.jupiter.api.Test;
42 import org.onap.policy.common.utils.services.Registry;
43 import org.onap.policy.models.base.PfModelException;
44 import org.onap.policy.models.base.PfModelRuntimeException;
45 import org.onap.policy.models.pap.concepts.PapPolicyIdentifier;
46 import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
47 import org.onap.policy.models.pdp.concepts.PdpGroup;
48 import org.onap.policy.models.pdp.concepts.PdpUpdate;
49 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifierOptVersion;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
52 import org.onap.policy.pap.main.PapConstants;
53 import org.springframework.test.util.ReflectionTestUtils;
54
55 public class TestProviderBase extends ProviderSuper {
56     private static final String EXPECTED_EXCEPTION = "expected exception";
57
58     private static final String POLICY1_NAME = "policyA";
59     private static final String POLICY1_VERSION = "1.2.3";
60     private static final String GROUP1_NAME = "groupA";
61     private static final String GROUP2_NAME = "groupB";
62     private static final String PDP1_TYPE = "pdpTypeA";
63     private static final String PDP2_TYPE = "pdpTypeB";
64     private static final String PDP3_TYPE = "pdpTypeC";
65     private static final String PDP4_TYPE = "pdpTypeD";
66     private static final String PDP1 = "pdpA";
67     private static final String PDP2 = "pdpB";
68     private static final String PDP3 = "pdpC";
69     private static final String PDP4 = "pdpD";
70
71     private MyProvider prov;
72
73     @AfterAll
74     public static void tearDownAfterClass() {
75         Registry.newRegistry();
76     }
77
78     /**
79      * Configures mocks and objects.
80      *
81      * @throws Exception if an error occurs
82      */
83     @Override
84     @BeforeEach
85     public void setUp() throws Exception {
86         super.setUp();
87         prov = new MyProvider();
88         super.initialize(prov);
89         when(toscaService.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json"));
90     }
91
92     @Test
93     void testProviderBase() {
94         assertSame(lockit, ReflectionTestUtils.getField(prov, "updateLock"));
95         assertSame(reqmap, ReflectionTestUtils.getField(prov, "requestMap"));
96     }
97
98     @Test
99     void testProcess() throws Exception {
100         prov.process(loadRequest(), this::handle);
101
102         assertGroup(getGroupUpdates(), GROUP1_NAME);
103
104         assertUpdate(getUpdateRequests(1), GROUP1_NAME, PDP1_TYPE, PDP1);
105
106         checkEmptyNotification();
107     }
108
109     @Test
110     void testProcess_PfRtEx() throws Exception {
111         PfModelRuntimeException ex = new PfModelRuntimeException(Status.BAD_REQUEST, EXPECTED_EXCEPTION);
112         when(pdpGroupService.updatePdpGroups(any())).thenThrow(ex);
113
114         assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isSameAs(ex);
115     }
116
117     @Test
118     void testProcess_RuntimeEx() throws Exception {
119         RuntimeException ex = new RuntimeException(EXPECTED_EXCEPTION);
120         when(pdpGroupService.updatePdpGroups(any())).thenThrow(ex);
121
122         assertThatThrownBy(() -> prov.process(loadEmptyRequest(), this::handle)).isInstanceOf(PfModelException.class)
123                         .hasMessage("request failed").hasCause(ex);
124     }
125
126     @Test
127     void testProcessPolicy_NoGroups() throws Exception {
128         when(pdpGroupService.getFilteredPdpGroups(any())).thenReturn(Collections.emptyList());
129
130         SessionData session =
131             new SessionData(DEFAULT_USER, toscaService, pdpGroupService, policyStatusService, policyAuditService);
132         ToscaConceptIdentifierOptVersion ident = new ToscaConceptIdentifierOptVersion(POLICY1_NAME, POLICY1_VERSION);
133         assertThatThrownBy(() -> prov.processPolicy(session, ident)).isInstanceOf(PfModelException.class)
134             .hasMessage("policy not supported by any PDP group: policyA 1.2.3");
135
136     }
137
138     @Test
139     void testGetPolicy() throws Exception {
140         PfModelException exc = new PfModelException(Status.CONFLICT, EXPECTED_EXCEPTION);
141         when(toscaService.getFilteredPolicyList(any())).thenThrow(exc);
142
143         ToscaConceptIdentifierOptVersion req = loadRequest();
144         assertThatThrownBy(() -> prov.process(req, this::handle)).isInstanceOf(PfModelRuntimeException.class)
145                         .hasCause(exc);
146     }
147
148     @Test
149     void testGetPolicy_NotFound() throws Exception {
150         when(toscaService.getFilteredPolicyList(any())).thenReturn(Collections.emptyList());
151
152         ToscaConceptIdentifierOptVersion req = loadRequest();
153         assertThatThrownBy(() -> prov.process(req, this::handle)).isInstanceOf(PfModelRuntimeException.class)
154                         .hasMessage("cannot find policy: policyA 1.2.3")
155                         .extracting(ex -> ((PfModelRuntimeException) ex).getErrorResponse().getResponseCode())
156                         .isEqualTo(Status.NOT_FOUND);
157     }
158
159     @Test
160     void testGetGroup() throws Exception {
161         when(pdpGroupService.getFilteredPdpGroups(any())).thenReturn(loadGroups("getGroupDao.json"))
162                         .thenReturn(loadGroups("groups.json"));
163
164         prov.process(loadRequest(), this::handle);
165
166         assertGroup(getGroupUpdates(), GROUP1_NAME);
167     }
168
169     @Test
170     void testUpgradeGroup() throws Exception {
171         /*
172          * Each subgroup has a different PDP type and name.
173          *
174          * Type is not supported by the first subgroup.
175          *
176          * Second subgroup matches.
177          *
178          * Third subgroup already contains the policy.
179          *
180          * Last subgroup matches.
181          */
182
183         when(pdpGroupService.getFilteredPdpGroups(any())).thenReturn(loadGroups("upgradeGroupDao.json"));
184
185         prov.clear();
186         prov.add(false, true, false, true);
187
188         prov.process(loadRequest(), this::handle);
189
190         assertGroup(getGroupUpdates(), GROUP1_NAME);
191
192         List<PdpUpdate> requests = getUpdateRequests(2);
193         assertUpdate(requests, GROUP1_NAME, PDP2_TYPE, PDP2);
194         assertUpdate(requests, GROUP1_NAME, PDP4_TYPE, PDP4);
195     }
196
197     @Test
198     void testUpgradeGroup_Multiple() throws Exception {
199         /*
200          * Policy data in the DB: policy1=type1, policy2=type2, policy3=type3,
201          * policy4=type1
202          *
203          * Group data in the DB: group1=(type1=pdp1, type3=pdp3) group2=(type2=pdp2)
204          *
205          * Request specifies: policy1, policy2, policy3, policy4
206          *
207          * Should create new versions of group1 and group2.
208          *
209          * Should update old versions of group1 and group2. Should also update new version
210          * of group1 twice.
211          *
212          * Should generate updates to pdp1, pdp2, and pdp3.
213          */
214
215         when(toscaService.getFilteredPolicyList(any())).thenReturn(loadPolicies("daoPolicyList.json"))
216                         .thenReturn(loadPolicies("upgradeGroupPolicy2.json"))
217                         .thenReturn(loadPolicies("upgradeGroupPolicy3.json"))
218                         .thenReturn(loadPolicies("upgradeGroupPolicy4.json"));
219
220         List<PdpGroup> groups1 = loadGroups("upgradeGroupGroup1.json");
221         List<PdpGroup> groups2 = loadGroups("upgradeGroupGroup2.json");
222
223         /*
224          * these are in pairs of (get-group, get-max-group) matching each policy in the
225          * request
226          */
227         // @formatter:off
228         when(pdpGroupService.getFilteredPdpGroups(any()))
229             .thenReturn(groups1).thenReturn(groups1)
230             .thenReturn(groups2).thenReturn(groups2)
231             .thenReturn(groups1).thenReturn(groups1)
232             .thenReturn(groups1).thenReturn(groups1);
233         // @formatter:on
234
235         // multiple policies in the request
236         PdpDeployPolicies request = loadFile("updateGroupReqMultiple.json", PdpDeployPolicies.class);
237
238         prov.process(request, (data, deploy) -> {
239             for (ToscaConceptIdentifierOptVersion policy : deploy.getPolicies()) {
240                 handle(data, policy);
241             }
242         });
243
244         // verify updates
245         List<PdpGroup> changes = getGroupUpdates();
246         assertGroup(changes, GROUP1_NAME);
247         assertGroup(changes, GROUP2_NAME);
248
249         List<PdpUpdate> requests = getUpdateRequests(3);
250         assertUpdateIgnorePolicy(requests, GROUP1_NAME, PDP1_TYPE, PDP1);
251         assertUpdateIgnorePolicy(requests, GROUP2_NAME, PDP2_TYPE, PDP2);
252         assertUpdateIgnorePolicy(requests, GROUP1_NAME, PDP3_TYPE, PDP3);
253     }
254
255     @Test
256     void testUpgradeGroup_NothingUpdated() throws Exception {
257         prov.clear();
258         prov.add(false);
259
260         prov.process(loadRequest(), this::handle);
261
262         verify(pdpGroupService, never()).createPdpGroups(any());
263         verify(pdpGroupService, never()).updatePdpGroups(any());
264         verify(reqmap, never()).addRequest(any(PdpUpdate.class));
265     }
266
267
268     protected void assertUpdate(List<PdpUpdate> updates, String groupName, String pdpType, String pdpName) {
269
270         PdpUpdate update = updates.remove(0);
271
272         assertEquals(PapConstants.PAP_NAME, update.getSource());
273         assertEquals(groupName, update.getPdpGroup());
274         assertEquals(pdpType, update.getPdpSubgroup());
275         assertEquals(pdpName, update.getName());
276         assertTrue(update.getPoliciesToBeDeployed().contains(policy1));
277     }
278
279     /**
280      * Loads a standard request.
281      *
282      * @return a standard request
283      */
284     protected ToscaConceptIdentifierOptVersion loadRequest() {
285         return loadRequest("requestBase.json");
286     }
287
288     /**
289      * Loads a request from a JSON file.
290      *
291      * @param fileName name of the file from which to load
292      * @return the request that was loaded
293      */
294     protected ToscaConceptIdentifierOptVersion loadRequest(String fileName) {
295         return loadFile(fileName, PapPolicyIdentifier.class).getGenericIdentifier();
296     }
297
298     /**
299      * Loads an empty request.
300      *
301      * @return an empty request
302      */
303     protected ToscaConceptIdentifierOptVersion loadEmptyRequest() {
304         return loadRequest("emptyRequestBase.json");
305     }
306
307     /**
308      * Handles a request by invoking the provider's processPolicy method.
309      *
310      * @param data session data
311      * @param request request to be handled
312      * @throws PfModelException if an error occurred
313      */
314     private void handle(SessionData data, ToscaConceptIdentifierOptVersion request) throws PfModelException {
315         prov.processPolicy(data, request);
316     }
317
318
319     private static class MyProvider extends ProviderBase {
320         /**
321          * Used to determine whether to make an update when
322          * makeUpdater() is called. The updater function removes an
323          * item from this queue each time it is invoked.
324          */
325         private final Queue<Boolean> shouldUpdate = new LinkedList<>();
326
327         /**
328          * Constructs the object and queues up several successful updates.
329          */
330         public MyProvider() {
331             for (int x = 0; x < 10; ++x) {
332                 shouldUpdate.add(true);
333             }
334         }
335
336         public void clear() {
337             shouldUpdate.clear();
338         }
339
340         public void add(Boolean... update) {
341             shouldUpdate.addAll(List.of(update));
342         }
343
344         @Override
345         protected Updater makeUpdater(SessionData data, ToscaPolicy policy,
346                         ToscaConceptIdentifierOptVersion desiredPolicy) {
347
348             return (group, subgroup) -> {
349                 if (shouldUpdate.remove()) {
350                     ToscaConceptIdentifier ident1 = policy.getIdentifier();
351
352                     // queue indicated that the update should succeed
353                     subgroup.getPolicies().add(ident1);
354
355                     ToscaPolicy testPolicy1 = data.getPolicy(new ToscaConceptIdentifierOptVersion(ident1));
356                     data.trackDeploy(testPolicy1, Collections.singleton(PDP1), GROUP1_NAME, PDP1_TYPE);
357                     data.trackUndeploy(ident1, Collections.singleton(PDP2), GROUP1_NAME, PDP2_TYPE);
358
359                     ToscaConceptIdentifier ident2 = new ToscaConceptIdentifier(POLICY1_NAME, "9.9.9");
360                     ToscaPolicy testPolicy2 = data.getPolicy(new ToscaConceptIdentifierOptVersion(ident2));
361                     data.trackDeploy(testPolicy2, Collections.singleton(PDP3), GROUP1_NAME, PDP3_TYPE);
362                     data.trackUndeploy(ident2, Collections.singleton(PDP4), GROUP1_NAME, PDP4_TYPE);
363                     return true;
364
365                 } else {
366                     // queue indicated that no update should be made this time
367                     return false;
368                 }
369             };
370         }
371     }
372 }