+ * Specification<Employee> specByProjectId = buildReferringEntitySpecification(criteria.getProjectId(), + * Employee_.project, Project_.id); + * Specification<Employee> specByProjectName = buildReferringEntitySpecification(criteria.getProjectName(), + * Employee_.project, Project_.name); + *+ * + * @param filter the filter object which contains a value, which needs to match or a flag if nullness is + * checked. + * @param reference the attribute of the static metamodel for the referring entity. + * @param valueField the attribute of the static metamodel of the referred entity, where the equality should be + * checked. + * @param
+ * Specification<Employee> specByEmployeeId = buildReferringEntitySpecification(criteria.getEmployeId(), + * Project_.employees, Employee_.id); + * Specification<Employee> specByEmployeeName = buildReferringEntitySpecification(criteria.getEmployeName(), + * Project_.project, Project_.name); + *+ * + * @param filter the filter object which contains a value, which needs to match or a flag if emptiness is + * checked. + * @param reference the attribute of the static metamodel for the referring entity. + * @param valueField the attribute of the static metamodel of the referred entity, where the equality should be + * checked. + * @param
+ * Specification<Employee> specByEmployeeId = buildReferringEntitySpecification( + * criteria.getEmployeId(), + * root -> root.get(Project_.company).join(Company_.employees), + * entity -> entity.get(Employee_.id)); + * Specification<Employee> specByProjectName = buildReferringEntitySpecification( + * criteria.getProjectName(), + * root -> root.get(Project_.project) + * entity -> entity.get(Project_.name)); + *+ * + * @param filter the filter object which contains a value, which needs to match or a flag if emptiness is + * checked. + * @param functionToEntity the function, which joins he current entity to the entity set, on which the filtering is applied. + * @param entityToColumn the function, which of the static metamodel of the referred entity, where the equality should be + * checked. + * @param
+ * Specification<Employee> specByEmployeeId = buildReferringEntitySpecification(criteria.getEmployeId(), + * Project_.employees, Employee_.id); + * Specification<Employee> specByEmployeeName = buildReferringEntitySpecification(criteria.getEmployeName(), + * Project_.project, Project_.name); + *+ * + * @param
+ * Specification<Employee> specByEmployeeId = buildReferringEntitySpecification(
+ * criteria.getEmployeId(),
+ * root -> root.get(Project_.company).join(Company_.employees),
+ * entity -> entity.get(Employee_.id));
+ * Specification<Employee> specByProjectName = buildReferringEntitySpecification(
+ * criteria.getProjectName(),
+ * root -> root.get(Project_.project)
+ * entity -> entity.get(Project_.name));
+ *
+ *
+ *
+ * @param likeUpperSpecification.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param value a {@link java.lang.String} object. + * @return a {@link org.springframework.data.jpa.domain.Specification} object. + */ + protected SpecificationdoesNotContainSpecification.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param value a {@link java.lang.String} object. + * @return a {@link org.springframework.data.jpa.domain.Specification} object. + */ + protected SpecificationbyFieldSpecified.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param specified a boolean. + * @parambyFieldEmptiness.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param specified a boolean. + * @paramvalueIn.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param values a {@link java.util.Collection} object. + * @paramvalueNotIn.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param values a {@link java.util.Collection} object. + * @paramgreaterThanOrEqualTo.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param value a X object. + * @paramgreaterThan.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param value a X object. + * @paramlessThanOrEqualTo.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param value a X object. + * @paramlessThan.
+ * + * @param metaclassFunction a {@link java.util.function.Function} object. + * @param value a X object. + * @paramwrapLikeQuery.
+ * + * @param txt a {@link java.lang.String} object. + * @return a {@link java.lang.String} object. + */ + protected String wrapLikeQuery(String txt) { + return "%" + txt.toUpperCase() + '%'; + } + + /** + *distinct.
+ * + * @param distinct a boolean. + * @return a {@link org.springframework.data.jpa.domain.Specification} object. + */ + protected Specification+ * For example the following could be a valid request: + * {@code /test-parameters?id.greaterThan=5&attr1.contains=something&attr2.specified=false} + *
+ * As Spring is unable to properly convert the types, unless + * specific {@link org.citrusframework.simulator.service.filter.Filter} class are used, we need to use fix type specific + * filters. + */ +@ParameterObject +@SuppressWarnings("common-java:DuplicatedBlocks") +public class TestParameterCriteria implements Serializable, Criteria { + + private static final long serialVersionUID = 1L; + + private StringFilter key; + + private StringFilter value; + + private InstantFilter createdDate; + + private InstantFilter lastModifiedDate; + + private LongFilter testResultId; + + private Boolean distinct; + + public TestParameterCriteria() {} + + public TestParameterCriteria(TestParameterCriteria other) { + this.key = other.key == null ? null : other.key.copy(); + this.value = other.value == null ? null : other.value.copy(); + this.createdDate = other.createdDate == null ? null : other.createdDate.copy(); + this.lastModifiedDate = other.lastModifiedDate == null ? null : other.lastModifiedDate.copy(); + this.testResultId = other.testResultId == null ? null : other.testResultId.copy(); + this.distinct = other.distinct; + } + + @Override + public TestParameterCriteria copy() { + return new TestParameterCriteria(this); + } + + public StringFilter getKey() { + return key; + } + + public StringFilter key() { + if (key == null) { + key = new StringFilter(); + } + return key; + } + + public void setKey(StringFilter key) { + this.key = key; + } + + public StringFilter getValue() { + return value; + } + + public StringFilter value() { + if (value == null) { + value = new StringFilter(); + } + return value; + } + + public void setValue(StringFilter value) { + this.value = value; + } + + public InstantFilter getCreatedDate() { + return createdDate; + } + + public InstantFilter createdDate() { + if (createdDate == null) { + createdDate = new InstantFilter(); + } + return createdDate; + } + + public void setCreatedDate(InstantFilter createdDate) { + this.createdDate = createdDate; + } + + public InstantFilter getLastModifiedDate() { + return lastModifiedDate; + } + + public InstantFilter lastModifiedDate() { + if (lastModifiedDate == null) { + lastModifiedDate = new InstantFilter(); + } + return lastModifiedDate; + } + + public void setLastModifiedDate(InstantFilter lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public LongFilter getTestResultId() { + return testResultId; + } + + public LongFilter testResultId() { + if (testResultId == null) { + testResultId = new LongFilter(); + } + return testResultId; + } + + public void setTestResultId(LongFilter testResultId) { + this.testResultId = testResultId; + } + + public Boolean getDistinct() { + return distinct; + } + + public void setDistinct(Boolean distinct) { + this.distinct = distinct; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final TestParameterCriteria that = (TestParameterCriteria) o; + return ( + Objects.equals(key, that.key) && + Objects.equals(value, that.value) && + Objects.equals(createdDate, that.createdDate) && + Objects.equals(lastModifiedDate, that.lastModifiedDate) && + Objects.equals(testResultId, that.testResultId) && + Objects.equals(distinct, that.distinct) + ); + } + + @Override + public int hashCode() { + return Objects.hash(key, value, createdDate, lastModifiedDate, testResultId, distinct); + } + + // prettier-ignore + @Override + public String toString() { + return "TestParameterCriteria{" + + (key != null ? "key=" + key + ", " : "") + + (value != null ? "value=" + value + ", " : "") + + (createdDate != null ? "createdDate=" + createdDate + ", " : "") + + (lastModifiedDate != null ? "lastModifiedDate=" + lastModifiedDate + ", " : "") + + (testResultId != null ? "testResultId=" + testResultId + ", " : "") + + (distinct != null ? "distinct=" + distinct + ", " : "") + + "}"; + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/TestResultCriteria.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/TestResultCriteria.java new file mode 100644 index 000000000..847f2e4c1 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/TestResultCriteria.java @@ -0,0 +1,289 @@ +package org.citrusframework.simulator.service.criteria; + +import org.citrusframework.simulator.service.filter.InstantFilter; +import org.citrusframework.simulator.service.filter.IntegerFilter; +import org.citrusframework.simulator.service.filter.LongFilter; +import org.citrusframework.simulator.service.filter.StringFilter; +import org.springdoc.core.annotations.ParameterObject; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Criteria class for the {@link org.citrusframework.simulator.model.TestResult} entity. This class is used + * in {@link org.citrusframework.simulator.web.rest.TestResultResource} to receive all the possible filtering options + * from the Http GET request parameters. + *
+ * For example the following could be a valid request: + * {@code /test-results?id.greaterThan=5&attr1.contains=something&attr2.specified=false} + *
+ * As Spring is unable to properly convert the types, unless + * specific {@link org.citrusframework.simulator.service.filter.Filter} class are used, we need to use fix type specific + * filters. + */ +@ParameterObject +@SuppressWarnings("common-java:DuplicatedBlocks") +public class TestResultCriteria implements Serializable, Criteria { + + private static final long serialVersionUID = 1L; + + private LongFilter id; + + private IntegerFilter status; + + private StringFilter testName; + + private StringFilter className; + + private StringFilter errorMessage; + + private StringFilter failureStack; + + private StringFilter failureType; + + private InstantFilter createdDate; + + private InstantFilter lastModifiedDate; + + private StringFilter testParameterKey; + + private Boolean distinct; + + public TestResultCriteria() {} + + public TestResultCriteria(TestResultCriteria other) { + this.id = other.id == null ? null : other.id.copy(); + this.status = other.status == null ? null : other.status.copy(); + this.testName = other.testName == null ? null : other.testName.copy(); + this.className = other.className == null ? null : other.className.copy(); + this.errorMessage = other.errorMessage == null ? null : other.errorMessage.copy(); + this.failureStack = other.failureStack == null ? null : other.failureStack.copy(); + this.failureType = other.failureType == null ? null : other.failureType.copy(); + this.createdDate = other.createdDate == null ? null : other.createdDate.copy(); + this.lastModifiedDate = other.lastModifiedDate == null ? null : other.lastModifiedDate.copy(); + this.testParameterKey = other.testParameterKey == null ? null : other.testParameterKey.copy(); + this.distinct = other.distinct; + } + + @Override + public TestResultCriteria copy() { + return new TestResultCriteria(this); + } + + public LongFilter getId() { + return id; + } + + public LongFilter id() { + if (id == null) { + id = new LongFilter(); + } + return id; + } + + public void setId(LongFilter id) { + this.id = id; + } + + public IntegerFilter getStatus() { + return status; + } + + public IntegerFilter status() { + if (status == null) { + status = new IntegerFilter(); + } + return status; + } + + public void setStatus(IntegerFilter status) { + this.status = status; + } + + public StringFilter getTestName() { + return testName; + } + + public StringFilter testName() { + if (testName == null) { + testName = new StringFilter(); + } + return testName; + } + + public void setTestName(StringFilter testName) { + this.testName = testName; + } + + public StringFilter getClassName() { + return className; + } + + public StringFilter className() { + if (className == null) { + className = new StringFilter(); + } + return className; + } + + public void setClassName(StringFilter className) { + this.className = className; + } + + public StringFilter getErrorMessage() { + return errorMessage; + } + + public StringFilter errorMessage() { + if (errorMessage == null) { + errorMessage = new StringFilter(); + } + return errorMessage; + } + + public void setErrorMessage(StringFilter errorMessage) { + this.errorMessage = errorMessage; + } + + public StringFilter getFailureStack() { + return failureStack; + } + + public StringFilter failureStack() { + if (failureStack == null) { + failureStack = new StringFilter(); + } + return failureStack; + } + + public void setFailureStack(StringFilter failureStack) { + this.failureStack = failureStack; + } + + public StringFilter getFailureType() { + return failureType; + } + + public StringFilter failureType() { + if (failureType == null) { + failureType = new StringFilter(); + } + return failureType; + } + + public void setFailureType(StringFilter failureType) { + this.failureType = failureType; + } + + public InstantFilter getCreatedDate() { + return createdDate; + } + + public InstantFilter createdDate() { + if (createdDate == null) { + createdDate = new InstantFilter(); + } + return createdDate; + } + + public void setCreatedDate(InstantFilter createdDate) { + this.createdDate = createdDate; + } + + public InstantFilter getLastModifiedDate() { + return lastModifiedDate; + } + + public InstantFilter lastModifiedDate() { + if (lastModifiedDate == null) { + lastModifiedDate = new InstantFilter(); + } + return lastModifiedDate; + } + + public void setLastModifiedDate(InstantFilter lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public StringFilter getTestParameterKey() { + return testParameterKey; + } + + public StringFilter testParameterId() { + if (testParameterKey == null) { + testParameterKey = new StringFilter(); + } + return testParameterKey; + } + + public void setTestParameterKey(StringFilter testParameterKey) { + this.testParameterKey = testParameterKey; + } + + public Boolean getDistinct() { + return distinct; + } + + public void setDistinct(Boolean distinct) { + this.distinct = distinct; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final TestResultCriteria that = (TestResultCriteria) o; + return ( + Objects.equals(id, that.id) && + Objects.equals(status, that.status) && + Objects.equals(testName, that.testName) && + Objects.equals(className, that.className) && + Objects.equals(errorMessage, that.errorMessage) && + Objects.equals(failureStack, that.failureStack) && + Objects.equals(failureType, that.failureType) && + Objects.equals(createdDate, that.createdDate) && + Objects.equals(lastModifiedDate, that.lastModifiedDate) && + Objects.equals(testParameterKey, that.testParameterKey) && + Objects.equals(distinct, that.distinct) + ); + } + + @Override + public int hashCode() { + return Objects.hash( + id, + status, + testName, + className, + errorMessage, + failureStack, + failureType, + createdDate, + lastModifiedDate, + testParameterKey, + distinct + ); + } + + // prettier-ignore + @Override + public String toString() { + return "TestResultCriteria{" + + (id != null ? "id=" + id + ", " : "") + + (status != null ? "status=" + status + ", " : "") + + (testName != null ? "testName=" + testName + ", " : "") + + (className != null ? "className=" + className + ", " : "") + + (errorMessage != null ? "errorMessage=" + errorMessage + ", " : "") + + (failureStack != null ? "failureStack=" + failureStack + ", " : "") + + (failureType != null ? "failureType=" + failureType + ", " : "") + + (createdDate != null ? "createdDate=" + createdDate + ", " : "") + + (lastModifiedDate != null ? "lastModifiedDate=" + lastModifiedDate + ", " : "") + + (testParameterKey != null ? "testParameterId=" + testParameterKey + ", " : "") + + (distinct != null ? "distinct=" + distinct + ", " : "") + + "}"; + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/dto/TestResultByStatus.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/dto/TestResultByStatus.java new file mode 100644 index 000000000..73e6794af --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/dto/TestResultByStatus.java @@ -0,0 +1,10 @@ +package org.citrusframework.simulator.service.dto; + +import java.util.Objects; + +public record TestResultByStatus(Long successful, Long failed, Long total) { + + public TestResultByStatus(Long successful, Long failed) { + this(Objects.isNull(successful) ? 0 : successful, Objects.isNull(failed)?0: failed, Objects.isNull(successful) || Objects.isNull(failed) ? 0: successful + failed); + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/Filter.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/Filter.java new file mode 100644 index 000000000..92c81f36d --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/Filter.java @@ -0,0 +1,200 @@ +package org.citrusframework.simulator.service.filter; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Base class for the various attribute filters. It can be added to a criteria class as a member, to support the + * following query parameters: + *
+ * fieldName.equals='something' + * fieldName.notEquals='somethingElse' + * fieldName.specified=true + * fieldName.specified=false + * fieldName.in='something','other' + * fieldName.notIn='something','other' + *+ */ +public class Filter
Constructor for Filter.
+ */ + public Filter() { + } + + /** + *Constructor for Filter.
+ * + * @param filter a {@link Filter} object. + */ + public Filter(Filtercopy.
+ * + * @return a {@link Filter} object. + */ + public FilterGetter for the field equals
.
Setter for the field equals
.
Getter for the field notEquals
.
Setter for the field notEquals
.
Getter for the field specified
.
Setter for the field specified
.
Getter for the field in
.
Setter for the field in
.
Getter for the field notIn
.
Setter for the field notIn
.
getFilterName.
+ * + * @return a {@link java.lang.String} object. + */ + protected String getFilterName() { + return getClass().getSimpleName(); + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/InstantFilter.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/InstantFilter.java new file mode 100644 index 000000000..bb5b0f3f9 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/InstantFilter.java @@ -0,0 +1,101 @@ +package org.citrusframework.simulator.service.filter; + +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.Instant; +import java.util.List; + +/** + * Filter class for {@link java.time.Instant} type attributes. + * + * @see RangeFilter + */ +public class InstantFilter extends RangeFilterConstructor for InstantFilter.
+ */ + public InstantFilter() { + } + + /** + *Constructor for InstantFilter.
+ * + * @param filter a {@link InstantFilter} object. + */ + public InstantFilter(InstantFilter filter) { + super(filter); + } + + /** {@inheritDoc} */ + @Override + public InstantFilter copy() { + return new InstantFilter(this); + } + + /** {@inheritDoc} */ + @Override + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + public InstantFilter setEquals(Instant equals) { + super.setEquals(equals); + return this; + } + + /** {@inheritDoc} */ + @Override + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + public InstantFilter setNotEquals(Instant equals) { + super.setNotEquals(equals); + return this; + } + + /** {@inheritDoc} */ + @Override + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + public InstantFilter setIn(ListConstructor for IntegerFilter.
+ */ + public IntegerFilter() { + } + + /** + *Constructor for IntegerFilter.
+ * + * @param filter a {@link IntegerFilter} object. + */ + public IntegerFilter(IntegerFilter filter) { + super(filter); + } + + /** + *copy.
+ * + * @return a {@link IntegerFilter} object. + */ + public IntegerFilter copy() { + return new IntegerFilter(this); + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/LongFilter.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/LongFilter.java new file mode 100644 index 000000000..579398c33 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/LongFilter.java @@ -0,0 +1,35 @@ +package org.citrusframework.simulator.service.filter; + +/** + * Filter class for {@link java.lang.Long} type attributes. + * + * @see RangeFilter + */ +public class LongFilter extends RangeFilterConstructor for LongFilter.
+ */ + public LongFilter() { + } + + /** + *Constructor for LongFilter.
+ * + * @param filter a {@link LongFilter} object. + */ + public LongFilter(LongFilter filter) { + super(filter); + } + + /** + *copy.
+ * + * @return a {@link LongFilter} object. + */ + public LongFilter copy() { + return new LongFilter(this); + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/RangeFilter.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/RangeFilter.java new file mode 100644 index 000000000..7c2da9665 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/filter/RangeFilter.java @@ -0,0 +1,182 @@ +package org.citrusframework.simulator.service.filter; + +import java.util.Objects; + +/** + * Filter class for Comparable types, where less than / greater than / etc relations could be interpreted. It can be + * added to a criteria class as a member, to support the following query parameters: + *+ * fieldName.equals=42 + * fieldName.notEquals=42 + * fieldName.specified=true + * fieldName.specified=false + * fieldName.in=43,42 + * fieldName.notIn=43,42 + * fieldName.greaterThan=41 + * fieldName.lessThan=44 + * fieldName.greaterThanOrEqual=42 + * fieldName.lessThanOrEqual=44 + *+ * Due to problems with the type conversions, the descendant classes should be used, where the generic type parameter + * is materialized. + * + * @param
Constructor for RangeFilter.
+ */ + public RangeFilter() { + } + + /** + *Constructor for RangeFilter.
+ * + * @param filter a {@link RangeFilter} object. + */ + public RangeFilter(RangeFilterGetter for the field greaterThan
.
Setter for the field greaterThan
.
Getter for the field lessThan
.
Setter for the field lessThan
.
Getter for the field greaterThanOrEqual
.
Setter for the field greaterThanOrEqual
.
Getter for the field lessThanOrEqual
.
Setter for the field lessThanOrEqual
.
+ * fieldName.equals='something'
+ * fieldName.notEquals='something'
+ * fieldName.specified=true
+ * fieldName.specified=false
+ * fieldName.in='something','other'
+ * fieldName.notIn='something','other'
+ * fieldName.contains='thing'
+ * fieldName.doesNotContain='thing'
+ *
+ */
+public class StringFilter extends FilterConstructor for StringFilter.
+ */ + public StringFilter() { + } + + /** + *Constructor for StringFilter.
+ * + * @param filter a {@link StringFilter} object. + */ + public StringFilter(StringFilter filter) { + super(filter); + contains = filter.contains; + doesNotContain = filter.doesNotContain; + } + + /** {@inheritDoc} */ + @Override + public StringFilter copy() { + return new StringFilter(this); + } + + /** + *Getter for the field contains
.
Setter for the field contains
.
Getter for the field doesNotContain
.
Setter for the field doesNotContain
.
+ * Pagination uses the same principles as the GitHub API,
+ * and follow RFC 5988 (Link header).
+ */
+public interface PaginationUtil {
+
+ String HEADER_X_TOTAL_COUNT = "X-Total-Count";
+ String HEADER_LINK_FORMAT = "<{0}>; rel=\"{1}\"";
+
+ /**
+ * Generate pagination headers for a Spring Data {@link org.springframework.data.domain.Page} object.
+ *
+ * @param uriBuilder The URI builder.
+ * @param page The page.
+ * @param