diff options
author | Pamela Dragosh <pdragosh@research.att.com> | 2019-04-12 11:03:44 -0400 |
---|---|---|
committer | Pamela Dragosh <pdragosh@research.att.com> | 2019-04-12 20:28:17 -0400 |
commit | 70736cfbf6ad1a068f8ee53adddd4faa3b6fa8a8 (patch) | |
tree | 6f883bb4cf79cd18eaac33c46446ac86a42934ce /main/src | |
parent | a5b035d9bb633cf5d520a62c451250db4b018a13 (diff) |
Add statistics and sonar cleanup and blacklist
* Adding in the statistics for decisions and errors.
* Cleaned up sonar issues and added code coverage.
* Sped up JUnit tests
* Fix JUnit issues with not finding application path
* Fix TestDecision not finding persistence.xml
* Fix for lingering statistics from previous runs. That
needs to be addressed at a later time.
* Changed persistence to use properties for configuration
of database rather than hard coding the persistence.xml
* Fix for Josh's comment to use else-if
* Changed to use apache Pair
* Added blacklist guard policy
Issue-ID: POLICY-1440
Change-Id: I56af8c3dcc82463f7381f1eaea7f1440b76200bd
Signed-off-by: Pamela Dragosh <pdragosh@research.att.com>
Diffstat (limited to 'main/src')
22 files changed, 440 insertions, 208 deletions
diff --git a/main/src/main/java/org/onap/policy/pdpx/main/comm/XacmlPdpPapRegistration.java b/main/src/main/java/org/onap/policy/pdpx/main/comm/XacmlPdpPapRegistration.java index b7421964..a848f523 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/comm/XacmlPdpPapRegistration.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/comm/XacmlPdpPapRegistration.java @@ -49,12 +49,10 @@ public class XacmlPdpPapRegistration { public void pdpRegistration(PdpStatus status) throws TopicSinkClientException { try { if (!client.send(status)) { - LOGGER.error("Failed to send to topic sink " + client.getTopic()); - return; + LOGGER.error("Failed to send to topic sink {}", client.getTopic()); } } catch (IllegalStateException e) { - LOGGER.error("Failed ot send to topic sink " + client.getTopic(), e); - return; + LOGGER.error("Failed ot send to topic sink {}", client.getTopic(), e); } } } diff --git a/main/src/main/java/org/onap/policy/pdpx/main/comm/listeners/XacmlPdpStateChangeListener.java b/main/src/main/java/org/onap/policy/pdpx/main/comm/listeners/XacmlPdpStateChangeListener.java index 3e24c3fe..84572d92 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/comm/listeners/XacmlPdpStateChangeListener.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/comm/listeners/XacmlPdpStateChangeListener.java @@ -63,7 +63,7 @@ public class XacmlPdpStateChangeListener extends ScoListener<PdpStateChange> { // Send State Change Status to PAP if (!client.send(newStatus)) { - LOGGER.error("failed to send to topic sink " + client.getTopic()); + LOGGER.error("failed to send to topic sink {}", client.getTopic()); throw new TopicSinkClientException("failed to send to topic sink " + client.getTopic()); } diff --git a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpApplicationManager.java b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpApplicationManager.java index 785d7591..db2ce553 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpApplicationManager.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpApplicationManager.java @@ -46,8 +46,6 @@ public class XacmlPdpApplicationManager { private static ServiceLoader<XacmlApplicationServiceProvider> applicationLoader; private static Map<String, XacmlApplicationServiceProvider> providerActionMap = new HashMap<>(); private static List<ToscaPolicyTypeIdentifier> toscaPolicyTypeIdents = new ArrayList<>(); - private static List<ToscaPolicyIdentifier> toscaPolicyIdents = new ArrayList<>(); - private static List<ToscaPolicy> toscaPolicies = new ArrayList<>(); private static Map<ToscaPolicy, XacmlApplicationServiceProvider> mapLoadedPolicies = new HashMap<>(); @@ -59,12 +57,20 @@ public class XacmlPdpApplicationManager { * One time to initialize the applications upon startup. */ public static void initializeApplications(Path applicationPath) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Initialization applications {}", applicationPath.toAbsolutePath()); + } // // If we have already done this // if (! needsInit) { - LOGGER.error("Already initialized the applications"); - return; + LOGGER.warn("Already initialized the applications {}", providerActionMap); + // + // I had to remove this because the JUnits kept failing - although I probably can + // add it back. The main() is hanging around during JUnits and initialization will + // fail. + // + // return } // // Load service @@ -74,8 +80,10 @@ public class XacmlPdpApplicationManager { // Iterate through the applications for actions and supported policy types // for (XacmlApplicationServiceProvider application : applicationLoader) { - LOGGER.info("Application {} supports {}", application.applicationName(), + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Application {} supports {}", application.applicationName(), application.supportedPolicyTypes()); + } // // We are not going to make this available unless the application can // install correctly. @@ -113,6 +121,8 @@ public class XacmlPdpApplicationManager { // we have initialized // needsInit = false; + LOGGER.info("Finished applications initialization {}", providerActionMap); + } public static XacmlApplicationServiceProvider findApplication(DecisionRequest request) { @@ -154,8 +164,10 @@ public class XacmlPdpApplicationManager { for (XacmlApplicationServiceProvider application : applicationLoader) { try { if (application.unloadPolicy(policy)) { - LOGGER.info("Unloaded ToscaPolicy {} from application {}", policy.getMetadata(), + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Unloaded ToscaPolicy {} from application {}", policy.getMetadata(), application.applicationName()); + } if (mapLoadedPolicies.remove(policy) == null) { LOGGER.error("Failed to remove unloaded policy {} from map size {}", policy.getMetadata(), mapLoadedPolicies.size()); @@ -183,8 +195,10 @@ public class XacmlPdpApplicationManager { // if (application.canSupportPolicyType(policy.getTypeIdentifier())) { if (application.loadPolicy(policy)) { - LOGGER.info("Loaded ToscaPolicy {} into application {}", policy.getMetadata(), + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Loaded ToscaPolicy {} into application {}", policy.getMetadata(), application.applicationName()); + } mapLoadedPolicies.put(policy, application); } return; @@ -217,7 +231,9 @@ public class XacmlPdpApplicationManager { // they can result in a valid directory being created. // Path path = Paths.get(basePath.toAbsolutePath().toString(), application.applicationName()); - LOGGER.info("initializeApplicationPath {} at this path {}", application.applicationName(), path); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("initializeApplicationPath {} at this path {}", application.applicationName(), path); + } // // Create that the directory if it does not exist. Ideally // this is only for testing, but could be used for production @@ -231,7 +247,7 @@ public class XacmlPdpApplicationManager { // Files.createDirectory(path); } catch (IOException e) { - LOGGER.error("Failed to create application directory", e); + LOGGER.error("Failed to create application directory {}", path.toAbsolutePath().toString(), e); } } // diff --git a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestController.java b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestController.java index c61bef24..37bab8ec 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestController.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestController.java @@ -175,6 +175,7 @@ public class XacmlPdpRestController { return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId) .entity(new DecisionProvider().fetchDecision(body)).build(); } catch (DecisionException e) { + XacmlPdpStatisticsManager.updateErrorCount(); return addLoggingHeaders( addVersionControlHeaders(Response.status((e.getErrorResponse().getResponseCode()))), requestId) .entity(e.getErrorResponse()).build(); diff --git a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestServer.java b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestServer.java index f7f6cc38..eee9717a 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestServer.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpRestServer.java @@ -63,6 +63,7 @@ public class XacmlPdpRestServer implements Startable { @Override public boolean start() { try { + LOGGER.info("Starting XacmlPdpRestServer..."); // // Initialize the applications - SEND PROPERTIES // @@ -86,6 +87,7 @@ public class XacmlPdpRestServer implements Startable { } server.start(); } + LOGGER.info("servers are started"); } catch (final Exception exp) { LOGGER.error("Failed to start xacml pdp http server", exp); return false; diff --git a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpStatisticsManager.java b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpStatisticsManager.java index cfdfa3d8..d209c09c 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpStatisticsManager.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/rest/XacmlPdpStatisticsManager.java @@ -28,6 +28,7 @@ public class XacmlPdpStatisticsManager { private static long totalPolicyTypesCount; private static long totalPoliciesCount; + private static long errorsCount; private static long permitDecisionsCount; private static long denyDecisionsCount; private static long indeterminantDecisionsCount; @@ -59,6 +60,15 @@ public class XacmlPdpStatisticsManager { } /** + * Method to update the number of error decisions. + * + * @return the errorDecisionsCount + */ + public static long updateErrorCount() { + return ++errorsCount; + } + + /** * Method to update the number of permit decisions. * * @return the permitDecisionsCount @@ -113,6 +123,15 @@ public class XacmlPdpStatisticsManager { } /** + * Returns the current value of errorDecisionsCount. + + * @return the permitDecisionsCount + */ + public static long getErrorCount() { + return errorsCount; + } + + /** * Returns the current value of permitDecisionsCount. * @return the permitDecisionsCount @@ -152,7 +171,9 @@ public class XacmlPdpStatisticsManager { * Reset all the statistics counts to 0. */ public static void resetAllStatistics() { + totalPolicyTypesCount = 0L; totalPoliciesCount = 0L; + errorsCount = 0L; permitDecisionsCount = 0L; denyDecisionsCount = 0L; indeterminantDecisionsCount = 0L; diff --git a/main/src/main/java/org/onap/policy/pdpx/main/rest/model/StatisticsReport.java b/main/src/main/java/org/onap/policy/pdpx/main/rest/model/StatisticsReport.java index 05933399..2544527e 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/rest/model/StatisticsReport.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/rest/model/StatisticsReport.java @@ -20,168 +20,25 @@ package org.onap.policy.pdpx.main.rest.model; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + /** * Class to represent statistics report of xacmlPdp service. * */ +@Getter +@Setter +@ToString public class StatisticsReport { private int code; private long totalPolicyTypesCount; private long totalPoliciesCount; + private long totalErrorCount; private long permitDecisionsCount; private long denyDecisionsCount; private long indeterminantDecisionsCount; private long notApplicableDecisionsCount; - - - /** - * Returns the code of this {@link StatisticsReport} instance. - * - * @return the code - */ - public int getCode() { - return code; - } - - /** - * Set code in this {@link StatisticsReport} instance. - * - * @param code the code to set - */ - public void setCode(final int code) { - this.code = code; - } - - /** - * Returns the totalPolicyTypesCount of this {@link StatisticsReport} instance. - * - * @return the totalPolicyTypesCount - */ - public long getTotalPolicyTypesCount() { - return totalPolicyTypesCount; - } - - /** - * Set totalPolicyTypesCount in this {@link StatisticsReport} instance. - * - * @param totalPolicyTypesCount the totalPolicyTypesCount to set - */ - public void setTotalPolicyTypesCount(long totalPolicyTypesCount) { - this.totalPolicyTypesCount = totalPolicyTypesCount; - } - - /** - * Returns the totalPoliciesCount of this {@link StatisticsReport} instance. - * - * @return the totalPoliciesCount - */ - public long getTotalPoliciesCount() { - return totalPoliciesCount; - } - - /** - * Set totalPoliciesCount in this {@link StatisticsReport} instance. - * - * @param totalPoliciesCount the totalPoliciesCount to set - */ - public void setTotalPoliciesCount(long totalPoliciesCount) { - this.totalPoliciesCount = totalPoliciesCount; - } - - /** - * Returns the permitDecisionsCount of this {@link StatisticsReport} instance. - * - * @return the permitDecisionsCount - */ - public long getPermitDecisionsCount() { - return permitDecisionsCount; - } - - /** - * Set permitDecisionsCount in this {@link StatisticsReport} instance. - * - * @param permitDecisionsCount the permitDecisionsCount to set - */ - public void setPermitDecisionsCount(long permitDecisionsCount) { - this.permitDecisionsCount = permitDecisionsCount; - } - - /** - * Returns the denyDecisionsCount of this {@link StatisticsReport} instance. - * - * @return the denyDecisionsCount - */ - public long getDenyDecisionsCount() { - return denyDecisionsCount; - } - - /** - * Set denyDecisionsCount in this {@link StatisticsReport} instance. - * - * @param denyDecisionsCount the denyDecisionsCount to set - */ - public void setDenyDecisionsCount(long denyDecisionsCount) { - this.denyDecisionsCount = denyDecisionsCount; - } - - /** - * Returns the indeterminantDecisionsCount of this {@link StatisticsReport} instance. - * - * @return the indeterminantDecisionsCount - */ - public long getIndeterminantDecisionsCount() { - return indeterminantDecisionsCount; - } - - /** - * Set indeterminantDecisionsCount in this {@link StatisticsReport} instance. - * - * @param indeterminantDecisionsCount the indeterminantDecisionsCount to set - */ - public void setIndeterminantDecisionsCount(long indeterminantDecisionsCount) { - this.indeterminantDecisionsCount = indeterminantDecisionsCount; - } - - /** - * Returns the notApplicableDecisionsCount of this {@link StatisticsReport} instance. - * - * @return the notApplicableDecisionsCount - */ - public long getNotApplicableDecisionsCount() { - return notApplicableDecisionsCount; - } - - /** - * Set notApplicableDecisionsCount in this {@link StatisticsReport} instance. - * - * @param notApplicableDecisionsCount the notApplicableDecisionsCount to set - */ - public void setNotApplicableDecisionsCount(long notApplicableDecisionsCount) { - this.notApplicableDecisionsCount = notApplicableDecisionsCount; - } - - /** - * {@inheritDoc}. - */ - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("StatisticsReport [code="); - builder.append(getCode()); - builder.append(", totalPolicyTypesCount="); - builder.append(getTotalPolicyTypesCount()); - builder.append(", totalPoliciesCount="); - builder.append(getTotalPoliciesCount()); - builder.append(", permitDecisionsCount="); - builder.append(getPermitDecisionsCount()); - builder.append(", denyDecisionsCount="); - builder.append(getDenyDecisionsCount()); - builder.append(", indeterminantDecisionsCount="); - builder.append(getIndeterminantDecisionsCount()); - builder.append(", notApplicableDecisionsCount="); - builder.append(getNotApplicableDecisionsCount()); - builder.append("]"); - return builder.toString(); - } } diff --git a/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/DecisionProvider.java b/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/DecisionProvider.java index 33178533..9cfb8a47 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/DecisionProvider.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/DecisionProvider.java @@ -20,13 +20,16 @@ package org.onap.policy.pdpx.main.rest.provider; -import javax.ws.rs.core.Response.Status; +import com.att.research.xacml.api.Response; +import com.att.research.xacml.api.Result; +import org.apache.commons.lang3.tuple.Pair; import org.onap.policy.models.decisions.concepts.DecisionException; import org.onap.policy.models.decisions.concepts.DecisionRequest; import org.onap.policy.models.decisions.concepts.DecisionResponse; import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider; import org.onap.policy.pdpx.main.rest.XacmlPdpApplicationManager; +import org.onap.policy.pdpx.main.rest.XacmlPdpStatisticsManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,9 +50,23 @@ public class DecisionProvider { // XacmlApplicationServiceProvider application = findApplication(request); // - // Cannot find application for action + // Found application for action // - return application.makeDecision(request); + Pair<DecisionResponse, Response> decision; + try { + decision = application.makeDecision(request); + } catch (Exception e) { + LOGGER.error("makeDecision failed", e); + throw e; + } + // + // Calculate statistics + // + this.calculateStatistic(decision.getValue()); + // + // Return the decision + // + return decision.getKey(); } private XacmlApplicationServiceProvider findApplication(DecisionRequest request) { @@ -57,7 +74,38 @@ public class DecisionProvider { if (application != null) { return application; } - throw new DecisionException(Status.BAD_REQUEST, "No application for action " + request.getAction()); + throw new DecisionException(javax.ws.rs.core.Response.Status.BAD_REQUEST, + "No application for action " + request.getAction()); + } + + private void calculateStatistic(Response xacmlResponse) { + + for (Result result : xacmlResponse.getResults()) { + switch (result.getDecision()) { + case PERMIT: + XacmlPdpStatisticsManager.updatePermitDecisionsCount(); + break; + + case DENY: + XacmlPdpStatisticsManager.updateDenyDecisionsCount(); + break; + + case INDETERMINATE: + case INDETERMINATE_DENY: + case INDETERMINATE_DENYPERMIT: + case INDETERMINATE_PERMIT: + XacmlPdpStatisticsManager.updateIndeterminantDecisionsCount(); + break; + + case NOTAPPLICABLE: + XacmlPdpStatisticsManager.updateNotApplicableDecisionsCount(); + break; + + default: + break; + + } + } } } diff --git a/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/StatisticsProvider.java b/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/StatisticsProvider.java index 59d3722c..95d67a67 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/StatisticsProvider.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/rest/provider/StatisticsProvider.java @@ -40,6 +40,7 @@ public class StatisticsProvider { report.setCode(XacmlPdpActivator.getCurrent().isAlive() ? 200 : 500); report.setTotalPolicyTypesCount(XacmlPdpStatisticsManager.getTotalPolicyTypesCount()); report.setTotalPoliciesCount(XacmlPdpStatisticsManager.getTotalPoliciesCount()); + report.setTotalErrorCount(XacmlPdpStatisticsManager.getErrorCount()); report.setPermitDecisionsCount(XacmlPdpStatisticsManager.getPermitDecisionsCount()); report.setDenyDecisionsCount(XacmlPdpStatisticsManager.getDenyDecisionsCount()); report.setIndeterminantDecisionsCount(XacmlPdpStatisticsManager.getIndeterminantDecisionsCount()); diff --git a/main/src/main/java/org/onap/policy/pdpx/main/startstop/XacmlPdpActivator.java b/main/src/main/java/org/onap/policy/pdpx/main/startstop/XacmlPdpActivator.java index 330fbd67..70dd2c42 100644 --- a/main/src/main/java/org/onap/policy/pdpx/main/startstop/XacmlPdpActivator.java +++ b/main/src/main/java/org/onap/policy/pdpx/main/startstop/XacmlPdpActivator.java @@ -98,6 +98,8 @@ public class XacmlPdpActivator extends ServiceManagerContainer { * @param topicProperties properties used to configure the topics */ public XacmlPdpActivator(final XacmlPdpParameterGroup xacmlPdpParameterGroup, Properties topicProperties) { + LOGGER.info("Activator initializing using {} and {}", xacmlPdpParameterGroup, topicProperties); + TopicEndpoint.manager.addTopicSinks(topicProperties); TopicEndpoint.manager.addTopicSources(topicProperties); diff --git a/main/src/main/resources/META-INF/persistence.xml b/main/src/main/resources/META-INF/persistence.xml new file mode 100644 index 00000000..e3f4a2f6 --- /dev/null +++ b/main/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP + ================================================================================ + Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> + + <persistence-unit name="OperationsHistoryPU" transaction-type="RESOURCE_LOCAL"> + <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + + <class>org.onap.policy.pdp.xacml.application.common.operationshistory.Dbao</class> + + <properties> + <property name="javax.persistence.schema-generation.database.action" value="create" /> + <property name="eclipselink.ddl-generation" value="create-or-extend-tables" /> + <property name="eclipselink.ddl-generation.output-mode" value="database" /> + <property name="eclipselink.logging.level" value="INFO" /> + </properties> + </persistence-unit> + +</persistence> +
\ No newline at end of file diff --git a/main/src/test/java/org/onap/policy/pdpx/main/PolicyXacmlPdpExceptionTest.java b/main/src/test/java/org/onap/policy/pdpx/main/PolicyXacmlPdpExceptionTest.java new file mode 100644 index 00000000..4dd02c62 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pdpx/main/PolicyXacmlPdpExceptionTest.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdpx.main; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.onap.policy.common.utils.test.ExceptionsTester; + +public class PolicyXacmlPdpExceptionTest { + + @Test + public void test() { + assertEquals(2, new ExceptionsTester().test(PolicyXacmlPdpException.class)); + } + +} diff --git a/main/src/test/java/org/onap/policy/pdpx/main/PolicyXacmlPdpRuntimeExceptionTest.java b/main/src/test/java/org/onap/policy/pdpx/main/PolicyXacmlPdpRuntimeExceptionTest.java new file mode 100644 index 00000000..80e69747 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pdpx/main/PolicyXacmlPdpRuntimeExceptionTest.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdpx.main; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.onap.policy.common.utils.test.ExceptionsTester; + +public class PolicyXacmlPdpRuntimeExceptionTest { + + @Test + public void test() { + assertEquals(2, new ExceptionsTester().test(PolicyXacmlPdpRuntimeException.class)); + } + + +} diff --git a/main/src/test/java/org/onap/policy/pdpx/main/rest/TestDecision.java b/main/src/test/java/org/onap/policy/pdpx/main/rest/TestDecision.java index b81336a5..3a1e98b1 100644 --- a/main/src/test/java/org/onap/policy/pdpx/main/rest/TestDecision.java +++ b/main/src/test/java/org/onap/policy/pdpx/main/rest/TestDecision.java @@ -38,17 +38,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; -import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -74,6 +68,7 @@ public class TestDecision { private static final Logger LOGGER = LoggerFactory.getLogger(TestDecision.class); private static Main main; + private static HttpClient client; @ClassRule public static final TemporaryFolder appsFolder = new TemporaryFolder(); @@ -81,15 +76,16 @@ public class TestDecision { /** * BeforeClass setup environment. * @throws IOException Cannot create temp apps folder + * @throws Exception exception if service does not start */ @BeforeClass - public static void beforeClass() throws IOException { + public static void beforeClass() throws Exception { System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog"); System.setProperty("org.eclipse.jetty.LEVEL", "OFF"); // // Copy test directory over of the application directories // - Path src = Paths.get("../packages/policy-xacmlpdp-tarball/src/main/resources/apps"); + Path src = Paths.get("src/test/resources/apps"); File apps = appsFolder.newFolder("apps"); Files.walk(src).forEach(source -> { copy(source, apps.toPath().resolve(src.relativize(source))); @@ -109,6 +105,16 @@ public class TestDecision { // Start the service // main = startXacmlPdpService(fileParams); + // + // Make sure it is running + // + if (!NetworkUtil.isTcpPortOpen("localhost", 6969, 20, 1000L)) { + throw new IllegalStateException("Cannot connect to port 6969"); + } + // + // Create a client + // + client = getNoAuthHttpClient(); } @AfterClass @@ -139,7 +145,9 @@ public class TestDecision { } @Test - public void testDecision_Guard() throws InterruptedException, IOException { + public void testDecision_Guard() throws KeyManagementException, NoSuchAlgorithmException, + ClassNotFoundException { + LOGGER.info("Running test testDecision_Guard"); DecisionRequest request = new DecisionRequest(); @@ -167,28 +175,17 @@ public class TestDecision { main.shutdown(); } - private DecisionResponse getDecision(DecisionRequest request) throws InterruptedException, IOException { - final ClientConfig clientConfig = new ClientConfig(); + private DecisionResponse getDecision(DecisionRequest request) { - final HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("healthcheck", "zb!XztG34"); - clientConfig.register(feature); - - final Client client = ClientBuilder.newClient(clientConfig); - final WebTarget webTarget = client.target("http://localhost:6969/policy/pdpx/v1/decision"); + Entity<DecisionRequest> entityRequest = Entity.entity(request, MediaType.APPLICATION_JSON); + Response response = client.post("", entityRequest, Collections.emptyMap()); - final Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); + assertEquals(200, response.getStatus()); - if (!NetworkUtil.isTcpPortOpen("localhost", 6969, 6, 10000L)) { - throw new IllegalStateException("Cannot connect to port 6969"); - } - - return invocationBuilder.post(Entity.json(request), DecisionResponse.class); + return HttpClient.getBody(response, DecisionResponse.class); } - private ErrorResponse getErrorDecision(DecisionRequest request) throws KeyManagementException, - NoSuchAlgorithmException, ClassNotFoundException { - - HttpClient client = getNoAuthHttpClient(); + private ErrorResponse getErrorDecision(DecisionRequest request) { Entity<DecisionRequest> entityRequest = Entity.entity(request, MediaType.APPLICATION_JSON); Response response = client.post("", entityRequest, Collections.emptyMap()); @@ -198,7 +195,7 @@ public class TestDecision { return HttpClient.getBody(response, ErrorResponse.class); } - private HttpClient getNoAuthHttpClient() + private static HttpClient getNoAuthHttpClient() throws KeyManagementException, NoSuchAlgorithmException, ClassNotFoundException { return HttpClient.factory.build(BusTopicParams.builder() .clientName("testDecisionClient") diff --git a/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpRestServer.java b/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpRestServer.java index 0deab9d0..f9f2abf3 100644 --- a/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpRestServer.java +++ b/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpRestServer.java @@ -44,8 +44,10 @@ import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import org.junit.After; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.junit.runners.MethodSorters; import org.onap.policy.common.endpoints.event.comm.client.TopicSinkClientException; import org.onap.policy.common.endpoints.report.HealthCheckReport; import org.onap.policy.common.utils.network.NetworkUtil; @@ -61,6 +63,7 @@ import org.slf4j.LoggerFactory; * Class to perform unit test of {@link XacmlPdpRestServer}. * */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestXacmlPdpRestServer { private static final Logger LOGGER = LoggerFactory.getLogger(TestXacmlPdpRestServer.class); @@ -99,10 +102,12 @@ public class TestXacmlPdpRestServer { if (NetworkUtil.isTcpPortOpen("localhost", 6969, 1, 1000L)) { if (main != null) { stopXacmlPdpService(main); + main = null; } if (restServer != null) { restServer.stop(); + restServer = null; } } } catch (IOException | PolicyXacmlPdpException e) { @@ -114,69 +119,84 @@ public class TestXacmlPdpRestServer { } @Test - public void testHealthCheckSuccess() throws IOException, InterruptedException, TopicSinkClientException { + public void test1HealthCheckSuccess() throws IOException, InterruptedException, TopicSinkClientException { + LOGGER.info("***************************** Running test1HealthCheckSuccess *****************************"); main = startXacmlPdpService(true); final Invocation.Builder invocationBuilder = sendHttpRequest(HEALTHCHECK_ENDPOINT); final HealthCheckReport report = invocationBuilder.get(HealthCheckReport.class); + LOGGER.info("test1HealthCheckSuccess health report {}", report); validateHealthCheckReport(NAME, SELF, true, 200, ALIVE, report); } @Test - public void testHealthCheckFailure() throws InterruptedException, IOException { + public void test7HealthCheckFailure() throws InterruptedException, IOException { + LOGGER.info("***************************** Running test7HealthCheckFailure *****************************"); final RestServerParameters restServerParams = new CommonTestData().getRestServerParameters(false); restServerParams.setName(CommonTestData.PDPX_GROUP_NAME); restServer = new XacmlPdpRestServer(restServerParams, applicationPath.getAbsolutePath()); restServer.start(); final Invocation.Builder invocationBuilder = sendHttpRequest(HEALTHCHECK_ENDPOINT); final HealthCheckReport report = invocationBuilder.get(HealthCheckReport.class); + LOGGER.info("test7HealthCheckFailure health report {}", report); validateHealthCheckReport(NAME, SELF, false, 500, NOT_ALIVE, report); assertTrue(restServer.isAlive()); assertTrue(restServer.toString().startsWith("XacmlPdpRestServer [servers=")); } @Test - public void testHttpsHealthCheckSuccess() throws Exception { + public void test2HttpsHealthCheckSuccess() throws Exception { + LOGGER.info("**************************** Running test2HttpsHealthCheckSuccess ****************************"); main = startXacmlPdpService(false); final Invocation.Builder invocationBuilder = sendHttpsRequest(HEALTHCHECK_ENDPOINT); final HealthCheckReport report = invocationBuilder.get(HealthCheckReport.class); + LOGGER.info("test2HttpsHealthCheckSuccess health report {}", report); validateHealthCheckReport(NAME, SELF, true, 200, ALIVE, report); } @Test - public void testStatistics_200() throws IOException, InterruptedException, TopicSinkClientException { + public void test4Statistics_200() throws IOException, InterruptedException, TopicSinkClientException { + LOGGER.info("***************************** Running test4Statistics_200 *****************************"); + XacmlPdpStatisticsManager.resetAllStatistics(); main = startXacmlPdpService(true); Invocation.Builder invocationBuilder = sendHttpRequest(STATISTICS_ENDPOINT); StatisticsReport report = invocationBuilder.get(StatisticsReport.class); + LOGGER.info("test4Statistics_200 health report {}", report); validateStatisticsReport(report, 0, 200); updateXacmlPdpStatistics(); invocationBuilder = sendHttpRequest(STATISTICS_ENDPOINT); report = invocationBuilder.get(StatisticsReport.class); + LOGGER.info("test4Statistics_200 health report {}", report); validateStatisticsReport(report, 1, 200); XacmlPdpStatisticsManager.resetAllStatistics(); } @Test - public void testStatistics_500() throws IOException, InterruptedException { + public void test5Statistics_500() throws IOException, InterruptedException { + LOGGER.info("***************************** Running test5Statistics_500 *****************************"); final RestServerParameters restServerParams = new CommonTestData().getRestServerParameters(false); restServerParams.setName(CommonTestData.PDPX_GROUP_NAME); restServer = new XacmlPdpRestServer(restServerParams, applicationPath.getAbsolutePath()); restServer.start(); final Invocation.Builder invocationBuilder = sendHttpRequest(STATISTICS_ENDPOINT); final StatisticsReport report = invocationBuilder.get(StatisticsReport.class); + LOGGER.info("test5Statistics_500 health report {}", report); validateStatisticsReport(report, 0, 500); XacmlPdpStatisticsManager.resetAllStatistics(); } @Test - public void testHttpsStatistic() throws Exception { + public void test6HttpsStatistic() throws Exception { + LOGGER.info("***************************** Running test6HttpsStatistic *****************************"); main = startXacmlPdpService(false); final Invocation.Builder invocationBuilder = sendHttpsRequest(STATISTICS_ENDPOINT); final StatisticsReport report = invocationBuilder.get(StatisticsReport.class); + LOGGER.info("test6HttpsStatistic health report {}", report); validateStatisticsReport(report, 0, 200); } @Test - public void testStatisticsConstructorIsPrivate() { + public void test3StatisticsConstructorIsPrivate() { + LOGGER.info("************************* Running test3StatisticsConstructorIsPrivate *************************"); try { final Constructor<XacmlPdpStatisticsManager> constructor = XacmlPdpStatisticsManager.class.getDeclaredConstructor(); @@ -224,9 +244,10 @@ public class TestXacmlPdpRestServer { final Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); - if (!NetworkUtil.isTcpPortOpen("localhost", 6969, 6, 10000L)) { - throw new IllegalStateException("cannot connect to port 6969"); + if (!NetworkUtil.isTcpPortOpen("localhost", 6969, 20, 1000L)) { + throw new IllegalStateException("Cannot connect to port 6969"); } + return invocationBuilder; } diff --git a/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpStatistics.java b/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpStatistics.java index 5b08aa80..6a762924 100644 --- a/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpStatistics.java +++ b/main/src/test/java/org/onap/policy/pdpx/main/rest/TestXacmlPdpStatistics.java @@ -76,6 +76,7 @@ public class TestXacmlPdpStatistics { @Test public void testXacmlPdpStatistics_200() throws PolicyXacmlPdpException, InterruptedException { try { + LOGGER.info("*************************** Running testXacmlPdpStatistics_200 ***************************"); final Main main = startXacmlPdpService(); StatisticsReport report = getXacmlPdpStatistics(); validateReport(report, 0, 200); @@ -93,6 +94,7 @@ public class TestXacmlPdpStatistics { @Test public void testXacmlPdpStatistics_500() throws InterruptedException { + LOGGER.info("***************************** Running testXacmlPdpStatistics_500 *****************************"); final RestServerParameters restServerParams = new CommonTestData().getRestServerParameters(false); restServerParams.setName(CommonTestData.PDPX_GROUP_NAME); final XacmlPdpRestServer restServer = new XacmlPdpRestServer(restServerParams, @@ -133,7 +135,7 @@ public class TestXacmlPdpStatistics { final Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); - if (!NetworkUtil.isTcpPortOpen("localhost", 6969, 6, 10000L)) { + if (!NetworkUtil.isTcpPortOpen("localhost", 6969, 20, 1000L)) { throw new IllegalStateException("Cannot connect to port 6969"); } diff --git a/main/src/test/resources/META-INF/persistence.xml b/main/src/test/resources/META-INF/persistence.xml new file mode 100644 index 00000000..d917c06b --- /dev/null +++ b/main/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP + ================================================================================ + Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> + + <persistence-unit name="PipEngineTest" transaction-type="RESOURCE_LOCAL"> + <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + + <class>org.onap.policy.pdp.xacml.application.common.operationshistory.Dbao</class> + + <properties> + <property name="eclipselink.ddl-generation" value="create-tables" /> + <property name="eclipselink.logging.level" value="FINE" /> + <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> + <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> + <property name="javax.persistence.schema-generation.create-source" value="metadata"/> + </properties> + </persistence-unit> + +</persistence> diff --git a/main/src/test/resources/apps/guard/xacml.properties b/main/src/test/resources/apps/guard/xacml.properties new file mode 100644 index 00000000..3d4d025c --- /dev/null +++ b/main/src/test/resources/apps/guard/xacml.properties @@ -0,0 +1,53 @@ +# +# Properties that the embedded PDP engine uses to configure and load +# +# Standard API Factories +# +xacml.dataTypeFactory=com.att.research.xacml.std.StdDataTypeFactory +xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory +xacml.pepEngineFactory=com.att.research.xacml.std.pep.StdEngineFactory +xacml.pipFinderFactory=com.att.research.xacml.std.pip.StdPIPFinderFactory +xacml.traceEngineFactory=com.att.research.xacml.std.trace.LoggingTraceEngineFactory +# +# AT&T PDP Implementation Factories +# +xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory +xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory +xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory +# +# ONAP PDP Implementation Factories +# +xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory + +# +# Use a root combining algorithm +# +xacml.att.policyFinderFactory.combineRootPolicies=urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-overrides + +# +# PIP Engine Definitions +# +count-recent-operations.classname=org.onap.policy.pdp.xacml.application.common.operationshistory.CountRecentOperationsPip +count-recent-operations.issuer=urn:org:onap:xacml:guard:count-recent-operations +count-recent-operations.name=CountRecentOperations +count-recent-operations.description=Returns operation counts based on time window +count-recent-operations.persistenceunit=OperationsHistoryPUTest + +get-operation-outcome.classname=org.onap.policy.pdp.xacml.application.common.operationshistory.GetOperationOutcomePip +get-operation-outcome.issuer=urn:org:onap:xacml:guard:get-operation-outcome +get-operation-outcome.name=GetOperationOutcome +get-operation-outcome.description=Returns operation outcome +get-operation-outcome.persistenceunit=OperationsHistoryPUTest + +# +# Make pips available to finder +# +xacml.pip.engines=count-recent-operations,get-operation-outcome + +# +# JPA Properties +# +javax.persistence.jdbc.driver=org.h2.Driver +javax.persistence.jdbc.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=FALSE +javax.persistence.jdbc.user=policy +javax.persistence.jdbc.password=P01icY diff --git a/main/src/test/resources/apps/monitoring/xacml.properties b/main/src/test/resources/apps/monitoring/xacml.properties new file mode 100644 index 00000000..5ea247cf --- /dev/null +++ b/main/src/test/resources/apps/monitoring/xacml.properties @@ -0,0 +1,31 @@ +# +# Properties that the embedded PDP engine uses to configure and load +# +# Standard API Factories +# +xacml.dataTypeFactory=com.att.research.xacml.std.StdDataTypeFactory +xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory +xacml.pepEngineFactory=com.att.research.xacml.std.pep.StdEngineFactory +xacml.pipFinderFactory=com.att.research.xacml.std.pip.StdPIPFinderFactory +xacml.traceEngineFactory=com.att.research.xacml.std.trace.LoggingTraceEngineFactory +# +# AT&T PDP Implementation Factories +# +xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory +xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory +xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory +# +# ONAP PDP Implementation Factories +# +xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory + +# +# Use a root combining algorithm +# +xacml.att.policyFinderFactory.combineRootPolicies=urn:com:att:xacml:3.0:policy-combining-algorithm:combined-permit-overrides + +# +# Policies to load +# +xacml.rootPolicies= +xacml.referencedPolicies=
\ No newline at end of file diff --git a/main/src/test/resources/apps/optimization/xacml.properties b/main/src/test/resources/apps/optimization/xacml.properties new file mode 100644 index 00000000..5ea247cf --- /dev/null +++ b/main/src/test/resources/apps/optimization/xacml.properties @@ -0,0 +1,31 @@ +# +# Properties that the embedded PDP engine uses to configure and load +# +# Standard API Factories +# +xacml.dataTypeFactory=com.att.research.xacml.std.StdDataTypeFactory +xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory +xacml.pepEngineFactory=com.att.research.xacml.std.pep.StdEngineFactory +xacml.pipFinderFactory=com.att.research.xacml.std.pip.StdPIPFinderFactory +xacml.traceEngineFactory=com.att.research.xacml.std.trace.LoggingTraceEngineFactory +# +# AT&T PDP Implementation Factories +# +xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory +xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory +xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory +# +# ONAP PDP Implementation Factories +# +xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory + +# +# Use a root combining algorithm +# +xacml.att.policyFinderFactory.combineRootPolicies=urn:com:att:xacml:3.0:policy-combining-algorithm:combined-permit-overrides + +# +# Policies to load +# +xacml.rootPolicies= +xacml.referencedPolicies=
\ No newline at end of file diff --git a/main/src/test/resources/parameters/XacmlPdpConfigParameters.json b/main/src/test/resources/parameters/XacmlPdpConfigParameters.json index ab52cc85..58eba71d 100644 --- a/main/src/test/resources/parameters/XacmlPdpConfigParameters.json +++ b/main/src/test/resources/parameters/XacmlPdpConfigParameters.json @@ -6,5 +6,5 @@ "userName": "healthcheck", "password": "zb!XztG34" }, - "applicationPath": "apps.test" + "applicationPath": "src/test/resources/apps" } diff --git a/main/src/test/resources/parameters/XacmlPdpConfigParameters_Https.json b/main/src/test/resources/parameters/XacmlPdpConfigParameters_Https.json index 92e6e908..ae5e1cbd 100644 --- a/main/src/test/resources/parameters/XacmlPdpConfigParameters_Https.json +++ b/main/src/test/resources/parameters/XacmlPdpConfigParameters_Https.json @@ -7,5 +7,5 @@ "password":"zb!XztG34", "https":true }, - "applicationPath": "apps.test" + "applicationPath": "src/test/resources/apps" }
\ No newline at end of file |