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