674169e851417d877f5e8ad746ef2ea2d80fedc2
[policy/xacml-pdp.git] / applications / optimization / src / test / java / org / onap / policy / xacml / pdp / application / optimization / OptimizationPdpApplicationTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019-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  *
20  * SPDX-License-Identifier: Apache-2.0
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.policy.xacml.pdp.application.optimization;
25
26 import static org.assertj.core.api.Assertions.assertThat;
27 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
28
29 import com.att.research.xacml.api.Response;
30 import com.google.common.collect.Lists;
31 import java.io.File;
32 import java.nio.file.Files;
33 import java.nio.file.Paths;
34 import java.util.Collection;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Properties;
40 import java.util.ServiceLoader;
41 import org.apache.commons.lang3.tuple.Pair;
42 import org.assertj.core.api.Condition;
43 import org.junit.BeforeClass;
44 import org.junit.ClassRule;
45 import org.junit.FixMethodOrder;
46 import org.junit.Test;
47 import org.junit.rules.TemporaryFolder;
48 import org.junit.runners.MethodSorters;
49 import org.onap.policy.common.utils.coder.CoderException;
50 import org.onap.policy.common.utils.coder.StandardCoder;
51 import org.onap.policy.common.utils.coder.StandardYamlCoder;
52 import org.onap.policy.common.utils.resources.ResourceUtils;
53 import org.onap.policy.common.utils.resources.TextFileUtils;
54 import org.onap.policy.models.decisions.concepts.DecisionRequest;
55 import org.onap.policy.models.decisions.concepts.DecisionResponse;
56 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
57 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
58 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
59 import org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate;
60 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
61 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
62 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
63 import org.onap.policy.pdp.xacml.xacmltest.TestUtils;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
68 public class OptimizationPdpApplicationTest {
69
70     private static final Logger LOGGER = LoggerFactory.getLogger(OptimizationPdpApplicationTest.class);
71     private static Properties properties = new Properties();
72     private static File propertiesFile;
73     private static XacmlApplicationServiceProvider service;
74     private static StandardCoder gson = new StandardCoder();
75     private static DecisionRequest baseRequest;
76     private static String[] listPolicyTypeFiles = {
77         "onap.policies.Optimization",
78         "onap.policies.optimization.Resource",
79         "onap.policies.optimization.Service",
80         "onap.policies.optimization.resource.AffinityPolicy",
81         "onap.policies.optimization.resource.DistancePolicy",
82         "onap.policies.optimization.resource.HpaPolicy",
83         "onap.policies.optimization.resource.OptimizationPolicy",
84         "onap.policies.optimization.resource.PciPolicy",
85         "onap.policies.optimization.service.QueryPolicy",
86         "onap.policies.optimization.service.SubscriberPolicy",
87         "onap.policies.optimization.resource.Vim_fit",
88         "onap.policies.optimization.resource.VnfPolicy"};
89
90     @ClassRule
91     public static final TemporaryFolder policyFolder = new TemporaryFolder();
92
93     /**
94      * Copies the xacml.properties and policies files into
95      * temporary folder and loads the service provider saving
96      * instance of provider off for other tests to use.
97      */
98     @BeforeClass
99     public static void setUp() throws Exception {
100         //
101         // Load Single Decision Request
102         //
103         baseRequest = gson.decode(
104                 TextFileUtils
105                     .getTextFileAsString(
106                             "src/test/resources/decision.optimization.input.json"),
107                     DecisionRequest.class);
108         //
109         // Setup our temporary folder
110         //
111         XacmlPolicyUtils.FileCreator myCreator = (String filename) -> policyFolder.newFile(filename);
112         propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties",
113                 properties, myCreator);
114         //
115         // Copy the test policy types into data area
116         //
117         for (String policy : listPolicyTypeFiles) {
118             String policyType = ResourceUtils.getResourceAsString("policytypes/" + policy + ".yaml");
119             LOGGER.info("Copying {}", policyType);
120             Files.write(Paths.get(policyFolder.getRoot().getAbsolutePath(), policy + "-1.0.0.yaml"),
121                     policyType.getBytes());
122         }
123         //
124         // Load service
125         //
126         ServiceLoader<XacmlApplicationServiceProvider> applicationLoader =
127                 ServiceLoader.load(XacmlApplicationServiceProvider.class);
128         //
129         // Iterate through Xacml application services and find
130         // the optimization service. Save it for use throughout
131         // all the Junit tests.
132         //
133         StringBuilder strDump = new StringBuilder("Loaded applications:" + XacmlPolicyUtils.LINE_SEPARATOR);
134         Iterator<XacmlApplicationServiceProvider> iterator = applicationLoader.iterator();
135         while (iterator.hasNext()) {
136             XacmlApplicationServiceProvider application = iterator.next();
137             //
138             // Is it our service?
139             //
140             if (application instanceof OptimizationPdpApplication) {
141                 //
142                 // Should be the first and only one
143                 //
144                 assertThat(service).isNull();
145                 service = application;
146             }
147             strDump.append(application.applicationName());
148             strDump.append(" supports ");
149             strDump.append(application.supportedPolicyTypes());
150             strDump.append(XacmlPolicyUtils.LINE_SEPARATOR);
151         }
152         LOGGER.debug("{}", strDump);
153         assertThat(service).isNotNull();
154         //
155         // Tell it to initialize based on the properties file
156         // we just built for it.
157         //
158         service.initialize(propertiesFile.toPath().getParent(), null);
159     }
160
161     /**
162      * Simply test some of the simple methods for the application.
163      */
164     @Test
165     public void test01Basics() {
166         //
167         // Make sure there's an application name
168         //
169         assertThat(service.applicationName()).isNotEmpty();
170         //
171         // Does it return the correct decisions
172         //
173         assertThat(service.actionDecisionsSupported().size()).isEqualTo(1);
174         assertThat(service.actionDecisionsSupported()).contains("optimize");
175         //
176         // Ensure it has the supported policy types and
177         // can support the correct policy types.
178         //
179         assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
180                 "onap.policies.optimization.resource.AffinityPolicy", "1.0.0"))).isTrue();
181         assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
182                 "onap.policies.optimization.service.SubscriberPolicy", "1.0.0"))).isTrue();
183         assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
184                 "onap.policies.optimization.service.CustomUseCase", "1.0.0"))).isTrue();
185         assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
186                 "onap.foobar", "1.0.0"))).isFalse();
187     }
188
189     /**
190      * With no policies loaded, there should be 0 policies returned.
191      *
192      * @throws CoderException CoderException
193      */
194     @Test
195     public void test02NoPolicies() throws CoderException {
196         //
197         // Ask for a decision when there are no policies loaded
198         //
199         LOGGER.info("Request {}", gson.encode(baseRequest));
200         Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
201         LOGGER.info("Decision {}", decision.getKey());
202
203         assertThat(decision.getKey()).isNotNull();
204         assertThat(decision.getKey().getPolicies()).isEmpty();
205     }
206
207     /**
208      * Should return ONLY default policies.
209      *
210      * @throws XacmlApplicationException could not load policies
211      */
212     @Test
213     public void test03OptimizationDefault() throws XacmlApplicationException {
214         //
215         // Now load all the optimization policies
216         //
217         List<ToscaPolicy> loadedPolicies = TestUtils.loadPolicies("src/test/resources/test-optimization-policies.yaml",
218                 service);
219         assertThat(loadedPolicies).isNotNull().hasSize(14);
220
221         validateDecisionCount(2);
222     }
223
224     /**
225      * Should only return default HPA policy type.
226      */
227     @SuppressWarnings("unchecked")
228     @Test
229     public void test04OptimizationDefaultHpa() {
230         //
231         // Add in policy type
232         //
233         List<String> policyTypes = Lists.newArrayList("onap.policies.optimization.resource.HpaPolicy");
234         baseRequest.getResource().put("policy-type", policyTypes);
235         //
236         // Ask for a decision for default HPA policy
237         //
238         DecisionResponse response = makeDecision();
239
240         assertThat(response).isNotNull();
241         assertThat(response.getPolicies()).hasSize(1);
242         response.getPolicies().forEach((key, value) -> {
243             assertThat(((Map<String, Object>) value)).containsEntry("type",
244                             "onap.policies.optimization.resource.HpaPolicy");
245         });
246         //
247         // Validate it
248         //
249         validateDecision(response, baseRequest);
250     }
251
252     /**
253      * Refine for US only policies.
254      */
255     @SuppressWarnings("unchecked")
256     @Test
257     public void test05OptimizationDefaultGeography() throws CoderException {
258         //
259         // Remove all the policy-type resources from the request
260         //
261         cleanOutResources();
262         //
263         // Add US to the geography list
264         //
265         ((List<String>) baseRequest.getResource().get("geography")).add("US");
266
267         validateDecisionCount(2);
268     }
269
270     /**
271      * Add more refinement for service.
272      */
273     @SuppressWarnings("unchecked")
274     @Test
275     public void test06OptimizationDefaultGeographyAndService() {
276         //
277         // Add vCPE to the service list
278         //
279         ((List<String>) baseRequest.getResource().get("services")).add("vCPE");
280
281         validateDecisionCount(3);
282     }
283
284     /**
285      * Add more refinement for specific resource.
286      */
287     @SuppressWarnings("unchecked")
288     @Test
289     public void test07OptimizationDefaultGeographyAndServiceAndResource() {
290         //
291         // Add vG to the resource list
292         //
293         ((List<String>) baseRequest.getResource().get("resources")).add("vG");
294
295         validateDecisionCount(6);
296     }
297
298     /**
299      * Now we need to add in subscriberName in order to get scope for gold.
300      */
301     @SuppressWarnings("unchecked")
302     @Test
303     public void test08OptimizationGeographyAndServiceAndResourceAndScopeIsGoldSubscriber() {
304         //
305         // Add gold as a scope
306         //
307         ((List<String>) baseRequest.getContext().get("subscriberName")).add("subscriber_a");
308
309         validateDecisionCount(6, 2);
310     }
311
312     /**
313      * Add a subscriber that should be platinum.
314      */
315     @SuppressWarnings("unchecked")
316     @Test
317     public void test09OptimizationGeographyAndServiceAndResourceAndScopeGoldOrPlatinumSubscriber() {
318         //
319         // Add platinum to the scope list: this is now gold OR platinum
320         //
321         ((List<String>) baseRequest.getResource().get("scope")).remove("gold");
322         ((List<String>) baseRequest.getContext().get("subscriberName")).add("subscriber_x");
323
324         validateDecisionCount(8, 2);
325     }
326
327     /**
328      * Remove gold subscriber, keep the platinum one.
329      */
330     @SuppressWarnings("unchecked")
331     @Test
332     public void test10OptimizationGeographyAndServiceAndResourceAndScopeNotGoldStillPlatinum() {
333         //
334         // Add gold as a scope
335         //
336         ((List<String>) baseRequest.getResource().get("scope")).remove("gold");
337         ((List<String>) baseRequest.getResource().get("scope")).remove("platinum");
338         ((List<String>) baseRequest.getContext().get("subscriberName")).remove("subscriber_a");
339
340         validateDecisionCount(7);
341     }
342
343     /**
344      * Filter by Affinity policy.
345      */
346     @Test
347     public void test11OptimizationPolicyTypeDefault() {
348         //
349         // Add in policy type
350         //
351         List<String> policyTypes = Lists.newArrayList("onap.policies.optimization.resource.AffinityPolicy");
352         baseRequest.getResource().put("policy-type", policyTypes);
353
354         validateDecisionCount(1);
355     }
356
357     /**
358      * Now filter by HPA policy type.
359      */
360     @SuppressWarnings("unchecked")
361     @Test
362     public void test12OptimizationPolicyTypeDefault() {
363         //
364         // Add in another policy type
365         //
366         ((List<String>) baseRequest.getResource().get("policy-type"))
367             .add("onap.policies.optimization.resource.HpaPolicy");
368
369         validateDecisionCount(2);
370     }
371
372     @Test
373     public void test999BadSubscriberPolicies() throws Exception {
374         final StandardYamlCoder yamlCoder = new StandardYamlCoder();
375         //
376         // Decode it
377         //
378         String policyYaml = ResourceUtils.getResourceAsString("src/test/resources/bad-subscriber-policies.yaml");
379         //
380         // Serialize it into a class
381         //
382         JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate();
383         ToscaServiceTemplate serviceTemplate = yamlCoder.decode(policyYaml, ToscaServiceTemplate.class);
384         jtst.fromAuthorative(serviceTemplate);
385         //
386         // Make sure all the fields are setup properly
387         //
388         ToscaServiceTemplate completedJtst = jtst.toAuthorative();
389         //
390         // Get the policies
391         //
392         for (Map<String, ToscaPolicy> policies : completedJtst.getToscaTopologyTemplate().getPolicies()) {
393             for (ToscaPolicy policy : policies.values()) {
394                 if ("missing-subscriberProperties".equals(policy.getName())) {
395                     assertThatExceptionOfType(XacmlApplicationException.class).isThrownBy(() ->
396                         service.loadPolicy(policy));
397                 } else if ("missing-subscriberName".equals(policy.getName())) {
398                     assertThatExceptionOfType(XacmlApplicationException.class).isThrownBy(() ->
399                         service.loadPolicy(policy));
400                 } else if ("missing-subscriberRole".equals(policy.getName())) {
401                     assertThatExceptionOfType(XacmlApplicationException.class).isThrownBy(() ->
402                         service.loadPolicy(policy));
403                 }
404             }
405         }
406     }
407
408     private DecisionResponse makeDecision() {
409         Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
410         LOGGER.info("Request Resources {}", baseRequest.getResource());
411         LOGGER.info("Decision {}", decision.getKey());
412         for (Entry<String, Object> entrySet : decision.getKey().getPolicies().entrySet()) {
413             LOGGER.info("Policy {}", entrySet.getKey());
414         }
415         return decision.getKey();
416     }
417
418     private DecisionResponse validateDecisionCount(int expectedPolicyCount) {
419         //
420         // Ask for a decision for default
421         //
422         DecisionResponse response = makeDecision();
423
424         assertThat(response).isNotNull();
425         assertThat(response.getPolicies()).hasSize(expectedPolicyCount);
426         //
427         // Validate it
428         //
429         validateDecision(response, baseRequest);
430
431         return response;
432     }
433
434     private void validateDecisionCount(int expectedPolicyCount, int expectedAdviceCount) {
435         DecisionResponse response = validateDecisionCount(expectedPolicyCount);
436
437         assertThat(response.getAdvice()).hasSize(expectedAdviceCount);
438     }
439
440     @SuppressWarnings("unchecked")
441     private void validateDecision(DecisionResponse decision, DecisionRequest request) {
442         for (Entry<String, Object> entrySet : decision.getPolicies().entrySet()) {
443             LOGGER.info("Decision Returned Policy {}", entrySet.getKey());
444             assertThat(entrySet.getValue()).isInstanceOf(Map.class);
445             Map<String, Object> policyContents = (Map<String, Object>) entrySet.getValue();
446             assertThat(policyContents).containsKey("properties");
447             assertThat(policyContents.get("properties")).isInstanceOf(Map.class);
448             Map<String, Object> policyProperties = (Map<String, Object>) policyContents.get("properties");
449
450             validateMatchable((Collection<String>) request.getResource().get("scope"),
451                     (Collection<String>) policyProperties.get("scope"));
452
453             validateMatchable((Collection<String>) request.getResource().get("services"),
454                     (Collection<String>) policyProperties.get("services"));
455
456             validateMatchable((Collection<String>) request.getResource().get("resources"),
457                     (Collection<String>) policyProperties.get("resources"));
458
459             validateMatchable((Collection<String>) request.getResource().get("geography"),
460                     (Collection<String>) policyProperties.get("geography"));
461         }
462     }
463
464     private void validateMatchable(Collection<String> requestList, Collection<String> policyProperties) {
465         LOGGER.info("Validating matchable: {} with {}", policyProperties, requestList);
466         //
467         // Null or empty implies '*' - that is any value is acceptable
468         // for this policy.
469         //
470         if (policyProperties == null || policyProperties.isEmpty()) {
471             return;
472         }
473         Condition<String> condition = new Condition<>(
474                 requestList::contains,
475                 "Request list is contained");
476         assertThat(policyProperties).haveAtLeast(1, condition);
477
478     }
479
480     @SuppressWarnings("unchecked")
481     private void cleanOutResources() {
482         ((List<String>) baseRequest.getResource().get("scope")).clear();
483         ((List<String>) baseRequest.getResource().get("services")).clear();
484         ((List<String>) baseRequest.getResource().get("resources")).clear();
485         ((List<String>) baseRequest.getResource().get("geography")).clear();
486         if (((List<String>) baseRequest.getResource().get("policy-type")) != null) {
487             baseRequest.getResource().remove("policy-type");
488         }
489     }
490 }