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