diff options
author | Jim Hahn <jrh3@att.com> | 2021-06-02 14:35:48 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2021-06-02 14:35:48 +0000 |
commit | 2ba648e483fe5f5ef953acb2b25135e9a3cbd742 (patch) | |
tree | 1af38fd6a6ada71ab88e2b412e8b504564eb09ba | |
parent | b1ebc97af3bf155a34100380435b5d21a2be774d (diff) | |
parent | 09e2bc57b947fb71c4dde9a8c0ded52f695abda1 (diff) |
Merge "Handling Policy deploy/undeploy audit models"
10 files changed, 842 insertions, 8 deletions
diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java b/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java index 844759367..378ae59b6 100644 --- a/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java +++ b/models-dao/src/main/java/org/onap/policy/models/dao/PfDao.java @@ -256,6 +256,17 @@ public interface PfDao { * * @param <T> the type of the objects to get, a subclass of {@link PfConcept} * @param someClass the class of the objects to get, a subclass of {@link PfConcept} + * @param orderBy field from class to order results by + * @param numRecords number of records to be retrieved + * @return the objects or null if no objects were retrieved + */ + <T extends PfConcept> List<T> getAll(Class<T> someClass, String orderBy, Integer numRecords); + + /** + * Get all the objects in the database of a given type. + * + * @param <T> the type of the objects to get, a subclass of {@link PfConcept} + * @param someClass the class of the objects to get, a subclass of {@link PfConcept} * @param name the name of the concepts for which to get all versions * @return the objects or null if no objects were retrieved */ diff --git a/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java b/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java index d27f3c6ed..336abf7df 100644 --- a/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java +++ b/models-dao/src/main/java/org/onap/policy/models/dao/impl/DefaultPfDao.java @@ -32,6 +32,7 @@ import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.TypedQuery; import javax.ws.rs.core.Response; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.models.base.PfConcept; import org.onap.policy.models.base.PfConceptKey; import org.onap.policy.models.base.PfGeneratedIdKey; @@ -72,6 +73,7 @@ public class DefaultPfDao implements PfDao { private static final String WHERE = " WHERE "; private static final String AND = " AND "; + private static final String ORDER_BY = " ORDER BY c."; private static final String NAME_FILTER = "c.key.name = :name"; private static final String VERSION_FILTER = "c.key.version = :version"; @@ -395,9 +397,8 @@ public class DefaultPfDao implements PfDao { try { PfFilter timeStampFilter = new PfFilterFactory().createFilter(someClass); - filterQueryString = timeStampFilter.addFilter(filterQueryString, - name, startTime, endTime, filterMap, sortOrder, getRecordNum); - + filterQueryString = timeStampFilter.addFilter(filterQueryString, name, startTime, endTime, filterMap, + sortOrder, getRecordNum); TypedQuery<T> query = mg.createQuery(setQueryTable(filterQueryString, someClass), someClass); @@ -427,7 +428,7 @@ public class DefaultPfDao implements PfDao { LOGGER.debug("filterQueryString is \"{}\"", filterQueryString); return query.getResultList(); - } finally { + } finally { mg.close(); } } @@ -505,6 +506,27 @@ public class DefaultPfDao implements PfDao { } @Override + public <T extends PfConcept> List<T> getAll(Class<T> someClass, String orderBy, Integer numRecords) { + + if (someClass == null) { + return Collections.emptyList(); + } + final var mg = getEntityManager(); + try { + String query = setQueryTable(SELECT_FROM_TABLE, someClass); + + if (StringUtils.isNotBlank(orderBy)) { + query = query.concat(ORDER_BY).concat(orderBy); + } + + return mg.createQuery(query, someClass).setMaxResults(numRecords) + .getResultList(); + } finally { + mg.close(); + } + } + + @Override public <T extends PfConcept> List<T> getAllVersionsByParent(final Class<T> someClass, final String parentKeyName) { if (someClass == null || parentKeyName == null) { return Collections.emptyList(); @@ -539,9 +561,8 @@ public class DefaultPfDao implements PfDao { } @Override - public <T extends PfConcept> List<T> getByTimestamp(final Class<T> someClass, - final PfGeneratedIdKey key, - final Instant timeStamp) { + public <T extends PfConcept> List<T> getByTimestamp(final Class<T> someClass, final PfGeneratedIdKey key, + final Instant timeStamp) { if (someClass == null || key == null || timeStamp == null) { return Collections.emptyList(); } diff --git a/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java b/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java index 66fc1b502..59fc9b482 100644 --- a/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java +++ b/models-dao/src/test/java/org/onap/policy/models/dao/EntityTest.java @@ -183,6 +183,7 @@ public class EntityTest { pfDao.get(null, nullTimeKey); pfDao.getAll(null); pfDao.getAll(null, nullKey); + pfDao.getAll(null, null, null); pfDao.getConcept(null, nullKey); pfDao.getConcept(PfConceptKey.class, nullKey); pfDao.getConcept(null, nullRefKey); diff --git a/models-pap/pom.xml b/models-pap/pom.xml index f2ac085a7..39508638e 100644 --- a/models-pap/pom.xml +++ b/models-pap/pom.xml @@ -1,6 +1,6 @@ <!-- ============LICENSE_START======================================================= - Copyright (C) 2019 Nordix Foundation. + Copyright (C) 2019-2021 Nordix Foundation. Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. ================================================================================ Licensed under the Apache License, Version 2.0 (the "License"); @@ -53,5 +53,15 @@ <artifactId>assertj-core</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/models-pap/src/main/java/org/onap/policy/models/pap/concepts/PolicyAudit.java b/models-pap/src/main/java/org/onap/policy/models/pap/concepts/PolicyAudit.java new file mode 100644 index 000000000..765d246a6 --- /dev/null +++ b/models-pap/src/main/java/org/onap/policy/models/pap/concepts/PolicyAudit.java @@ -0,0 +1,50 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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.models.pap.concepts; + +import java.time.Instant; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * Audit info on policy actions. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PolicyAudit { + + public enum AuditAction { + DEPLOYMENT, UNDEPLOYMENT + } + + private Long auditId; + private String pdpGroup; + private String pdpType; + private ToscaConceptIdentifier policy; + private AuditAction action; + private Instant timestamp; + private String user; +} diff --git a/models-pap/src/main/java/org/onap/policy/models/pap/persistence/concepts/JpaPolicyAudit.java b/models-pap/src/main/java/org/onap/policy/models/pap/persistence/concepts/JpaPolicyAudit.java new file mode 100644 index 000000000..b31af8ea0 --- /dev/null +++ b/models-pap/src/main/java/org/onap/policy/models/pap/persistence/concepts/JpaPolicyAudit.java @@ -0,0 +1,191 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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.models.pap.persistence.concepts; + +import java.time.Instant; +import java.util.Date; +import java.util.List; +import javax.persistence.Column; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.Index; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.onap.policy.common.utils.validation.Assertions; +import org.onap.policy.models.base.PfAuthorative; +import org.onap.policy.models.base.PfConcept; +import org.onap.policy.models.base.PfGeneratedIdKey; +import org.onap.policy.models.base.PfKey; +import org.onap.policy.models.base.PfReferenceKey; +import org.onap.policy.models.base.validation.annotations.VerifyKey; +import org.onap.policy.models.pap.concepts.PolicyAudit; +import org.onap.policy.models.pap.concepts.PolicyAudit.AuditAction; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * Entity to keep the records on policy actions for audit. + * + * @author Adheli Tavares (adheli.tavares@est.tech) + * + */ +@Entity +@Table(name = "JpaPolicyAudit", indexes = {@Index(name = "JpaPolicyAuditIndex_timestamp", columnList = "timeStamp")}) +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@Data +@EqualsAndHashCode(callSuper = false) +public class JpaPolicyAudit extends PfConcept implements PfAuthorative<PolicyAudit> { + private static final long serialVersionUID = -2935734300607322191L; + + @EmbeddedId + @Column + @NotNull + @VerifyKey(versionNotNull = true) + private PfGeneratedIdKey key; + + @Column + private String pdpGroup; + + @Column + private String pdpType; + + @Column + @NotNull + private AuditAction action; + + @Column + @Temporal(TemporalType.TIMESTAMP) + @NotNull + private Date timeStamp; + + @Column + private String user; + + /** + * Default constructor. + */ + public JpaPolicyAudit() { + key = new PfGeneratedIdKey(); + } + + /** + * Constructor from an authorative. + * + * @param audit authorative model + */ + public JpaPolicyAudit(PolicyAudit audit) { + fromAuthorative(audit); + } + + /** + * Constructor as a copy. + * + * @param copyConcept original entity to be copied + */ + public JpaPolicyAudit(JpaPolicyAudit copyConcept) { + this.key = new PfGeneratedIdKey(copyConcept.getKey()); + this.pdpGroup = copyConcept.getPdpGroup(); + this.pdpType = copyConcept.getPdpType(); + this.action = copyConcept.getAction(); + this.timeStamp = copyConcept.getTimeStamp(); + this.user = copyConcept.getUser(); + } + + @Override + public int compareTo(PfConcept o) { + if (o == null) { + return -1; + } + if (this == o) { + return 0; + } + if (getClass() != o.getClass()) { + return getClass().getName().compareTo(o.getClass().getName()); + } + + final JpaPolicyAudit other = (JpaPolicyAudit) o; + + // @formatter:off + return new CompareToBuilder() + .append(key, other.key) + .append(pdpGroup, other.pdpGroup) + .append(pdpType, other.pdpType) + .append(action, other.action) + .append(timeStamp, other.timeStamp) + .append(user, other.user) + .toComparison(); + // @formatter:on + } + + @Override + public PolicyAudit toAuthorative() { + ToscaConceptIdentifier policyIdent = new ToscaConceptIdentifier(key.getName(), key.getVersion()); + + // @formatter:off + return PolicyAudit.builder() + .auditId(key.getGeneratedId()) + .pdpGroup(pdpGroup) + .pdpType(pdpType) + .policy(policyIdent) + .action(action) + .timestamp(timeStamp == null ? null : timeStamp.toInstant()) + .user(user) + .build(); + // @formatter:on + } + + @Override + public void fromAuthorative(PolicyAudit authorativeConcept) { + if (authorativeConcept.getPolicy() != null) { + final ToscaConceptIdentifier policy = authorativeConcept.getPolicy(); + key = new PfGeneratedIdKey(policy.getName(), policy.getVersion(), authorativeConcept.getAuditId()); + } else { + key = new PfGeneratedIdKey(); + } + + pdpGroup = authorativeConcept.getPdpGroup(); + pdpType = authorativeConcept.getPdpType(); + action = authorativeConcept.getAction(); + timeStamp = authorativeConcept.getTimestamp() == null ? Date.from(Instant.now()) + : Date.from(authorativeConcept.getTimestamp()); + user = authorativeConcept.getUser(); + } + + @Override + public List<PfKey> getKeys() { + return getKey().getKeys(); + } + + @Override + public void clean() { + key.clean(); + + pdpGroup = Assertions.validateStringParameter("pdpGroup", pdpGroup, PfReferenceKey.LOCAL_NAME_REGEXP); + pdpType = Assertions.validateStringParameter("pdpType", pdpType, PfReferenceKey.LOCAL_NAME_REGEXP); + user = Assertions.validateStringParameter("user", user, PfReferenceKey.LOCAL_NAME_REGEXP); + } +} diff --git a/models-pap/src/main/java/org/onap/policy/models/pap/persistence/provider/PolicyAuditProvider.java b/models-pap/src/main/java/org/onap/policy/models/pap/persistence/provider/PolicyAuditProvider.java new file mode 100644 index 000000000..c117beefa --- /dev/null +++ b/models-pap/src/main/java/org/onap/policy/models/pap/persistence/provider/PolicyAuditProvider.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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.models.pap.persistence.provider; + +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.ws.rs.core.Response; +import lombok.Builder; +import lombok.Data; +import lombok.NonNull; +import org.apache.commons.lang3.StringUtils; +import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.dao.PfDao; +import org.onap.policy.models.pap.concepts.PolicyAudit; +import org.onap.policy.models.pap.concepts.PolicyAudit.AuditAction; +import org.onap.policy.models.pap.persistence.concepts.JpaPolicyAudit; + +/** + * Provider for Policy Audit. + * + * @author Adheli Tavares (adheli.tavares@est.tech) + * + */ +public class PolicyAuditProvider { + + private static final Integer DEFAULT_MAX_RECORDS = 100; + private static final String DESCENDING_ORDER = "DESC"; + + /** + * Create audit records. + * + * @param audits list of policy audit + */ + public void createAuditRecords(@NonNull PfDao dao, @NonNull final List<PolicyAudit> audits) { + List<JpaPolicyAudit> jpaAudits = audits.stream().map(JpaPolicyAudit::new).collect(Collectors.toList()); + + BeanValidationResult result = new BeanValidationResult("createAuditRecords", jpaAudits); + + int count = 0; + for (JpaPolicyAudit jpaAudit: jpaAudits) { + result.addResult(jpaAudit.validate(String.valueOf(count++))); + } + + if (!result.isValid()) { + throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, result.getResult()); + } + + dao.createCollection(jpaAudits); + } + + /** + * Collect all audit records. + * + * @param numRecords number of records to be collected + * @return list of {@link PolicyAudit} records + */ + public List<PolicyAudit> getAuditRecords(@NonNull PfDao dao, @NonNull Integer numRecords) { + numRecords = numRecords > DEFAULT_MAX_RECORDS ? DEFAULT_MAX_RECORDS : numRecords; + + // @formatter:off + return dao.getAll(JpaPolicyAudit.class, "timeStamp DESC", numRecords) + .stream() + .map(JpaPolicyAudit::toAuthorative) + .collect(Collectors.toList()); + // @formatter:on + } + + /** + * Collect audit records based on filters at {@link AuditFilter}. + * + * @param auditFilter {@link AuditFilter} object with filters for search + * @param numRecords number of records to be collected + * @return list of {@link PolicyAudit} records + */ + public List<PolicyAudit> getAuditRecords(@NonNull PfDao dao, @NonNull AuditFilter auditFilter, + @NonNull Integer numRecords) { + numRecords = numRecords > DEFAULT_MAX_RECORDS ? DEFAULT_MAX_RECORDS : numRecords; + + Map<String, Object> filter = new HashMap<>(); + if (StringUtils.isNotBlank(auditFilter.getPdpGroup())) { + filter.put("pdpGroup", auditFilter.getPdpGroup()); + } + + if (auditFilter.getAction() != null) { + filter.put("action", auditFilter.getAction()); + } + + // @formatter:off + return dao.getFiltered(JpaPolicyAudit.class, + auditFilter.getName(), auditFilter.getVersion(), + auditFilter.getFromDate(), auditFilter.getToDate(), + filter, DESCENDING_ORDER, numRecords) + .stream().map(JpaPolicyAudit::toAuthorative).collect(Collectors.toList()); + // @formatter:on + } + + /** + * Create a filter for looking for audit records. + * name - policy name + * version - policy version + * pdpGroup - PDP group that policy might be related + * action - type of action/operation realized on policy + * fromDate - start of period in case of time interval search + */ + @Data + @Builder + protected static class AuditFilter { + private String name; + private String version; + private AuditAction action; + private String pdpGroup; + private Instant fromDate; + private Instant toDate; + } +} diff --git a/models-pap/src/test/java/org/onap/policy/models/pap/persistence/concepts/JpaPolicyAuditTest.java b/models-pap/src/test/java/org/onap/policy/models/pap/persistence/concepts/JpaPolicyAuditTest.java new file mode 100644 index 000000000..4f8693304 --- /dev/null +++ b/models-pap/src/test/java/org/onap/policy/models/pap/persistence/concepts/JpaPolicyAuditTest.java @@ -0,0 +1,126 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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.models.pap.persistence.concepts; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.models.pap.concepts.PolicyAudit; +import org.onap.policy.models.pap.concepts.PolicyAudit.AuditAction; +import org.onap.policy.models.pdp.concepts.PdpPolicyStatus; +import org.onap.policy.models.pdp.concepts.PdpPolicyStatus.State; +import org.onap.policy.models.pdp.persistence.concepts.JpaPdpPolicyStatus; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +public class JpaPolicyAuditTest { + + private static final ToscaConceptIdentifier MY_POLICY = new ToscaConceptIdentifier("MyPolicy", "1.2.3"); + private static final String PDP_GROUP = "pdpGroupxyz"; + private static final String USER = "user"; + + PolicyAudit audit; + + /** + * Setup an audit for usage on unit tests. + */ + @Before + public void setup() { + audit = PolicyAudit.builder().auditId(1L).pdpGroup(PDP_GROUP).pdpType("pdpType").policy(MY_POLICY) + .action(AuditAction.DEPLOYMENT).timestamp(Instant.now().truncatedTo(ChronoUnit.SECONDS)).build(); + } + + @Test + public void testCompareTo() { + JpaPolicyAudit jpaAudit = new JpaPolicyAudit(audit); + assertEquals(-1, jpaAudit.compareTo(null)); + assertEquals(0, jpaAudit.compareTo(jpaAudit)); + assertEquals(0, jpaAudit.compareTo(new JpaPolicyAudit(jpaAudit))); + + PdpPolicyStatus idw = PdpPolicyStatus.builder().deploy(true).state(State.SUCCESS).pdpGroup(PDP_GROUP) + .pdpId("wId").policy(MY_POLICY).policyType(MY_POLICY).build(); + JpaPdpPolicyStatus jpaStatus = new JpaPdpPolicyStatus(idw); + assertNotEquals(0, jpaAudit.compareTo(jpaStatus)); + } + + @Test + public void testKeys() { + JpaPolicyAudit jpaAudit = new JpaPolicyAudit(); + assertThat(jpaAudit.getKeys()).isNotNull(); + assertTrue(jpaAudit.getKey().isNullKey()); + + jpaAudit = new JpaPolicyAudit(audit); + assertFalse(jpaAudit.getKey().isNullKey()); + } + + @Test + public void testClean() { + audit.setUser(" user"); + JpaPolicyAudit jpaAudit = new JpaPolicyAudit(audit); + assertThatNoException().isThrownBy(() -> jpaAudit.clean()); + assertEquals(USER, jpaAudit.getUser()); + } + + @Test + public void testToAuthorative() { + audit.setUser(USER); + JpaPolicyAudit jpaAudit = new JpaPolicyAudit(audit); + PolicyAudit convertedAudit = jpaAudit.toAuthorative(); + + assertEquals(audit, convertedAudit); + assertEquals(USER, convertedAudit.getUser()); + + JpaPolicyAudit jpaAuditWithNullKey = new JpaPolicyAudit(); + PolicyAudit convertedAudit2 = jpaAuditWithNullKey.toAuthorative(); + assertTrue(convertedAudit2.getPolicy().asConceptKey().isNullKey()); + + } + + @Test + public void testConversionsWithRequiredOnly() { + audit = PolicyAudit.builder().policy(MY_POLICY).action(AuditAction.DEPLOYMENT) + .timestamp(Instant.now().truncatedTo(ChronoUnit.SECONDS)).build(); + + JpaPolicyAudit jpaAudit = new JpaPolicyAudit(audit); + PolicyAudit convertedAudit = jpaAudit.toAuthorative(); + + assertEquals(audit, convertedAudit); + assertTrue(jpaAudit.validate("jpaAudit").isValid()); + } + + @Test + public void testValidation() { + PolicyAudit invalidAudit = PolicyAudit.builder().pdpGroup(PDP_GROUP).user(USER).build(); + + JpaPolicyAudit jpaAudit = new JpaPolicyAudit(invalidAudit); + + BeanValidationResult result = jpaAudit.validate("jpaAudit"); + assertFalse(result.isValid()); + } +} diff --git a/models-pap/src/test/java/org/onap/policy/models/pap/persistence/provider/PolicyAuditProviderTest.java b/models-pap/src/test/java/org/onap/policy/models/pap/persistence/provider/PolicyAuditProviderTest.java new file mode 100644 index 000000000..da231dc7b --- /dev/null +++ b/models-pap/src/test/java/org/onap/policy/models/pap/persistence/provider/PolicyAuditProviderTest.java @@ -0,0 +1,241 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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.models.pap.persistence.provider; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.TimeUnit; +import org.awaitility.Awaitility; +import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.dao.DaoParameters; +import org.onap.policy.models.dao.PfDao; +import org.onap.policy.models.dao.PfDaoFactory; +import org.onap.policy.models.dao.impl.DefaultPfDao; +import org.onap.policy.models.pap.concepts.PolicyAudit; +import org.onap.policy.models.pap.concepts.PolicyAudit.AuditAction; +import org.onap.policy.models.pap.persistence.provider.PolicyAuditProvider.AuditFilter; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * Class for unit testing {@link PolicyAuditProvider}. + * + * @author Adheli Tavares (adheli.tavares@est.tech) + * + */ +public class PolicyAuditProviderTest { + + private static final String FIELD_IS_NULL = "%s is marked .*ull but is null"; + private static final String GROUP_A = "groupA"; + private static final String GROUP_B = "groupB"; + private static final ToscaConceptIdentifier MY_POLICY = new ToscaConceptIdentifier("MyPolicy", "1.2.3"); + private static final ToscaConceptIdentifier MY_POLICY2 = new ToscaConceptIdentifier("MyPolicyB", "2.3.4"); + private static final Integer NUMBER_RECORDS = 10; + + private PfDao pfDao; + + /** + * Set up the DAO towards the database. + * + * @throws Exception on database errors + */ + @Before + public void setupDao() throws Exception { + final DaoParameters daoParameters = new DaoParameters(); + daoParameters.setPluginClass(DefaultPfDao.class.getName()); + + daoParameters.setPersistenceUnit("ToscaConceptTest"); + + Properties jdbcProperties = new Properties(); + jdbcProperties.setProperty(PersistenceUnitProperties.JDBC_USER, "policy"); + jdbcProperties.setProperty(PersistenceUnitProperties.JDBC_PASSWORD, "P01icY"); + + if (System.getProperty("USE-MARIADB") != null) { + jdbcProperties.setProperty(PersistenceUnitProperties.JDBC_DRIVER, "org.mariadb.jdbc.Driver"); + jdbcProperties.setProperty(PersistenceUnitProperties.JDBC_URL, "jdbc:mariadb://localhost:3306/policy"); + } else { + jdbcProperties.setProperty(PersistenceUnitProperties.JDBC_DRIVER, "org.h2.Driver"); + jdbcProperties.setProperty(PersistenceUnitProperties.JDBC_URL, "jdbc:h2:mem:PolicyAuditProviderTest"); + } + + daoParameters.setJdbcProperties(jdbcProperties); + + pfDao = new PfDaoFactory().createPfDao(daoParameters); + pfDao.init(daoParameters); + } + + @After + public void teardown() { + pfDao.close(); + } + + @Test + public void testCreatePolicyAudit() { + PolicyAuditProvider provider = new PolicyAuditProvider(); + + Instant date = Instant.now(); + provider.createAuditRecords(pfDao, generatePolicyAudits(date, GROUP_A, MY_POLICY)); + + List<PolicyAudit> records = provider.getAuditRecords(pfDao, NUMBER_RECORDS); + assertThat(records).hasSize(2); + + // as the start date is 10 min ahead of first record, shouldn't return any records + List<PolicyAudit> emptyList = provider.getAuditRecords(pfDao, + AuditFilter.builder().fromDate(Instant.now().plusSeconds(600)).build(), 600); + assertThat(emptyList).isEmpty(); + } + + @Test + public void testCreatePolicyAuditInvalid() { + PolicyAuditProvider provider = new PolicyAuditProvider(); + + List<PolicyAudit> audits = List.of(PolicyAudit.builder().pdpType("pdpType").action(AuditAction.DEPLOYMENT) + .timestamp(Instant.now()).build()); + + assertThrows(PfModelRuntimeException.class, () -> provider.createAuditRecords(pfDao, audits)); + + List<PolicyAudit> records = provider.getAuditRecords(pfDao, NUMBER_RECORDS); + assertThat(records).isEmpty(); + } + + @Test + public void testFilters() { + PolicyAuditProvider provider = new PolicyAuditProvider(); + + Instant date = Instant.now().truncatedTo(ChronoUnit.SECONDS); + System.out.println(date); + provider.createAuditRecords(pfDao, generatePolicyAudits(date, GROUP_A, MY_POLICY)); + provider.createAuditRecords(pfDao, generatePolicyAudits(date, GROUP_B, MY_POLICY)); + provider.createAuditRecords(pfDao, generatePolicyAudits(date, GROUP_B, MY_POLICY2)); + Awaitility.await().pollDelay(3, TimeUnit.SECONDS).until(() -> { + return true; + }); + + List<PolicyAudit> records = provider.getAuditRecords(pfDao, + AuditFilter.builder().fromDate(date).toDate(Instant.now()).build(), NUMBER_RECORDS); + assertThat(records).hasSize(6); + + List<PolicyAudit> recordsWithGroupB = + provider.getAuditRecords(pfDao, AuditFilter.builder().pdpGroup(GROUP_B).build(), NUMBER_RECORDS); + assertThat(recordsWithGroupB).hasSize(4); + + List<PolicyAudit> recordsWithActionDeploy = provider.getAuditRecords(pfDao, + AuditFilter.builder().action(AuditAction.DEPLOYMENT).build(), NUMBER_RECORDS); + assertThat(recordsWithActionDeploy).hasSize(3); + + List<PolicyAudit> recordsWithMyPolicy = provider.getAuditRecords(pfDao, + AuditFilter.builder().name(MY_POLICY.getName()).version(MY_POLICY.getVersion()).build(), + NUMBER_RECORDS); + assertThat(recordsWithMyPolicy).hasSize(4); + } + + @Test + public void testLoadRecordsForLimit() { + PolicyAuditProvider provider = new PolicyAuditProvider(); + + List<PolicyAudit> loadAudits = new ArrayList<>(); + + // going to create 102 records. + for (int i = 0; i <= 50; i++) { + loadAudits.addAll(generatePolicyAudits(Instant.now().plusSeconds(i), GROUP_A, MY_POLICY)); + } + + provider.createAuditRecords(pfDao, loadAudits); + + List<PolicyAudit> records = provider.getAuditRecords(pfDao, NUMBER_RECORDS); + assertThat(records).hasSize(10); + + // check that is being ordered + assertTrue(records.get(0).getTimestamp().isAfter(records.get(9).getTimestamp())); + assertEquals(loadAudits.get(loadAudits.size() - 1).getTimestamp(), records.get(0).getTimestamp()); + + // try to get 102 records should return 100 + records = provider.getAuditRecords(pfDao, 102); + assertThat(records).hasSize(100); + } + + @Test + public void policyProviderExceptions() { + PolicyAuditProvider provider = new PolicyAuditProvider(); + + assertThatThrownBy(() -> { + provider.createAuditRecords(null, null); + }).hasMessageMatching(String.format(FIELD_IS_NULL, "dao")); + + assertThatThrownBy(() -> { + provider.createAuditRecords(pfDao, null); + }).hasMessageMatching(String.format(FIELD_IS_NULL, "audits")); + + assertThatThrownBy(() -> { + provider.getAuditRecords(null, NUMBER_RECORDS); + }).hasMessageMatching(String.format(FIELD_IS_NULL, "dao")); + + assertThatThrownBy(() -> { + provider.getAuditRecords(pfDao, null); + }).hasMessageMatching(String.format(FIELD_IS_NULL, "numRecords")); + + assertThatThrownBy(() -> { + provider.getAuditRecords(null, AuditFilter.builder().build(), NUMBER_RECORDS); + }).hasMessageMatching(String.format(FIELD_IS_NULL, "dao")); + + assertThatThrownBy(() -> { + provider.getAuditRecords(pfDao, AuditFilter.builder().build(), null); + }).hasMessageMatching(String.format(FIELD_IS_NULL, "numRecords")); + + assertThatThrownBy(() -> { + provider.getAuditRecords(pfDao, null, NUMBER_RECORDS); + }).hasMessageMatching(String.format(FIELD_IS_NULL, "auditFilter")); + } + + private List<PolicyAudit> generatePolicyAudits(Instant date, String group, ToscaConceptIdentifier policy) { + // @formatter:off + PolicyAudit deploy = PolicyAudit.builder() + .pdpGroup(group) + .pdpType("pdpType") + .policy(policy) + .action(AuditAction.DEPLOYMENT) + .timestamp(date.truncatedTo(ChronoUnit.SECONDS)) + .build(); + + PolicyAudit undeploy = PolicyAudit.builder() + .pdpGroup(group) + .pdpType("pdpType") + .policy(policy) + .action(AuditAction.UNDEPLOYMENT) + .timestamp(date.plusSeconds(1).truncatedTo(ChronoUnit.SECONDS)) + .build(); + // @formatter:on + + return List.of(deploy, undeploy); + } +} diff --git a/models-pap/src/test/resources/META-INF/persistence.xml b/models-pap/src/test/resources/META-INF/persistence.xml new file mode 100644 index 000000000..58e2deca3 --- /dev/null +++ b/models-pap/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Copyright (C) 2021 Nordix Foundation. + ================================================================================ + 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========================================================= +--> + +<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> + <persistence-unit name="ToscaConceptTest" transaction-type="RESOURCE_LOCAL"> + <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + + <class>org.onap.policy.models.pap.persistence.concepts.JpaPolicyAudit</class> + + <properties> + <property name="eclipselink.target-database" value="MySQL" /> + <property name="eclipselink.ddl-generation" value="drop-and-create-tables" /> + <property name="eclipselink.ddl-generation.output-mode" value="database" /> + <property name="eclipselink.logging.level" value="INFO" /> + + <property name="eclipselink.logging.level" value="ALL" /> + <property name="eclipselink.logging.level.jpa" value="ALL" /> + <property name="eclipselink.logging.level.ddl" value="ALL" /> + <property name="eclipselink.logging.level.connection" value="ALL" /> + <property name="eclipselink.logging.level.sql" value="ALL" /> + <property name="eclipselink.logging.level.transaction" value="ALL" /> + <property name="eclipselink.logging.level.sequencing" value="ALL" /> + <property name="eclipselink.logging.level.server" value="ALL" /> + <property name="eclipselink.logging.level.query" value="ALL" /> + <property name="eclipselink.logging.level.properties" value="ALL" /> + </properties> + </persistence-unit> +</persistence> |