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