Skip to content

Commit

Permalink
Merge pull request citrusframework#204 from postfinance/fix/test_resu…
Browse files Browse the repository at this point in the history
…lt_truncation

fix: TestResult error message truncation
  • Loading branch information
tschlat authored Nov 7, 2023
2 parents 408b563 + 8390e9d commit 45ea8f8
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2023 the original author or authors.
*
* 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.
*/

package org.citrusframework.simulator.model;

import jakarta.persistence.Column;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

/**
* EntityUtils - A utility class for handling data model operations.
*
* This class provides utility methods for working with data models and entities.
*
* @author Thorsten Schlathoelter
*/
public class EntityUtils {

private static final Logger logger = LoggerFactory.getLogger(EntityUtils.class);

private EntityUtils() {
// only static access
}

/**
* Truncate a string value to fit the column size specified for an entity property.
*
* This method is used to truncate a string value to fit the maximum column size
* specified in the corresponding entity class for a specific property. If the provided
* value is longer than the specified column size, it will be silently truncated to match
* the column size.
*
* The column size is determined using reflection. If reflection fails due to the entityProperty not
* matching a field, an exception is thrown to indicate a misconfiguration. If it fails due to a
* security manager preventing reflection, truncation will be silently ignored. This is only harmful
* if a value requires truncation, which will be detected by the persistence layer.
*
* @param entityClass The class of the entity containing the property definition.
* @param entityProperty The name of the property for which the column size is defined.
* @param value The value to be truncated.
* @return The truncated value.
*/
public static String truncateToColumnSize(Class<?> entityClass, String entityProperty, String value) {
if (StringUtils.hasLength(value)) {
try {
int size = entityClass.getDeclaredField(entityProperty)
.getAnnotation(Column.class)
.length();
int inLength = value.length();
if (inLength > size) {
return value.substring(0, size);
}
} catch (NoSuchFieldException e) {
throw new CitrusRuntimeException(String.format("entityProperty '%s' unknown for class '%s'", entityProperty, entityClass.getName()));
} catch (SecurityException e) {
logger.warn("Unable to perform truncation for entity class '{}' and field '{}'.", entityClass, entityProperty, e);
}
}

return value;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,11 @@
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.springframework.util.StringUtils;

import java.io.Serial;
import java.io.Serializable;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
Expand Down Expand Up @@ -135,20 +130,8 @@ public String getErrorMessage() {
return errorMessage;
}

public void setErrorMessage(String errorMessage) throws ErrorMessageTruncationException {
this.errorMessage = errorMessage;
if (StringUtils.hasLength(this.errorMessage)) {
try {
int size = getClass().getDeclaredField("errorMessage").getAnnotation(Column.class).length();
int inLength = this.errorMessage.length();
if (inLength > size) {
this.errorMessage = this.errorMessage.substring(0, size);
}
} catch (SecurityException | NoSuchFieldException ex) {
throw new ErrorMessageTruncationException(
String.format("Error truncating error message '%s'!", errorMessage), ex);
}
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = EntityUtils.truncateToColumnSize(getClass(), "errorMessage", errorMessage);
}

public Set<ScenarioParameter> getScenarioParameters() {
Expand Down Expand Up @@ -227,12 +210,6 @@ public static Status fromId(int id) {
}
}

public static class ErrorMessageTruncationException extends Exception {
public ErrorMessageTruncationException(String errorMessage, Exception exception) {
super(errorMessage, exception);
}
}

public static class ScenarioExecutionBuilder {

private final ScenarioExecution scenarioExecution = new ScenarioExecution();
Expand Down Expand Up @@ -265,7 +242,7 @@ public ScenarioExecutionBuilder status(Status status) {
return this;
}

public ScenarioExecutionBuilder errorMessage(String errorMessage) throws ErrorMessageTruncationException {
public ScenarioExecutionBuilder errorMessage(String errorMessage) {
scenarioExecution.setErrorMessage(errorMessage);
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public TestResult(org.citrusframework.TestResult testResult) {
className = testResult.getClassName();
testResult.getParameters().forEach((key, value) -> testParameters.add(new TestParameter(key, value.toString(), this)));
// NOte that the cause will be dropped: testResult.getCause()
errorMessage = testResult.getErrorMessage();
errorMessage = EntityUtils.truncateToColumnSize(getClass(), "errorMessage", testResult.getErrorMessage());
failureStack = testResult.getFailureStack();
failureType = testResult.getFailureType();
}
Expand Down Expand Up @@ -268,7 +268,7 @@ public TestResultBuilder className(String className) {
}

public TestResultBuilder errorMessage(String errorMessage) {
testResult.errorMessage = errorMessage;
testResult.errorMessage = EntityUtils.truncateToColumnSize(TestResult.class, "errorMessage", errorMessage);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
package org.citrusframework.simulator.service;

import jakarta.transaction.Transactional;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.citrusframework.TestAction;
import org.citrusframework.TestCase;
Expand All @@ -29,15 +37,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
* Service for persisting and retrieving {@link ScenarioExecution} data.
*/
Expand Down Expand Up @@ -115,7 +114,7 @@ private void completeScenarioExecution(ScenarioExecution.Status status, TestCase
try (StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter)) {
cause.printStackTrace(printWriter);
scenarioExecution.setErrorMessage(stringWriter.toString());
} catch (IOException | ScenarioExecution.ErrorMessageTruncationException e) {
} catch (IOException e) {
logger.warn("Failed to write error message to scenario execution!", e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import static org.assertj.core.api.Assertions.assertThat;

class EntityUtils {
class EntityTestUtils {

private EntityUtils() {
private EntityTestUtils() {
// Static utility class
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.citrusframework.simulator.model;

import static org.junit.jupiter.api.Assertions.assertEquals;

import jakarta.persistence.Column;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class EntityUtilsTest {

@Test
void truncateToColumnSizePerformed() {
String message = "The quick brown fox jumps over the lazy dog";
String truncatedMessage = EntityUtils.truncateToColumnSize(TestEntity.class, "message",
message);
assertEquals("The quick brown fox jumps over the la", truncatedMessage);
}

@Test
void truncateToColumnSizeNotPerformed() {
String message = "Waltz, bad nymph, for quick jigs vex";
String truncatedMessage = EntityUtils.truncateToColumnSize(TestEntity.class, "message",
message);
assertEquals(message, truncatedMessage);
}

@Test
void truncateToColumnSizeExceptionOnUnknownProperty() {
String message = "Sphinx of black quartz, judge my vow.";
Assertions.assertThrows(CitrusRuntimeException.class, () -> EntityUtils.truncateToColumnSize(TestEntity.class, "otherMessage",
message));
}

public static class TestEntity {

@Column(length=37)
String message;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class MessageHeaderTest {

@Test
void equalsVerifier() throws Exception {
EntityUtils.equalsVerifier(MessageHeader.class);
EntityTestUtils.equalsVerifier(MessageHeader.class);

MessageHeader messageHeader1 = new MessageHeader();
messageHeader1.setHeaderId(1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class MessageTest {

@Test
void equalsVerifier() throws Exception {
EntityUtils.equalsVerifier(Message.class);
EntityTestUtils.equalsVerifier(Message.class);

Message message1 = new Message();
message1.setMessageId(1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class TestParameterTest {

@Test
void equalsVerifier() throws Exception {
EntityUtils.equalsVerifier(TestParameter.class);
EntityTestUtils.equalsVerifier(TestParameter.class);
TestParameter testParameter1 = new TestParameter("key", "", TestResult.builder().id(1L).build());

TestParameter testParameter2 = new TestParameter(testParameter1.getKey(), testParameter1.getValue(), testParameter1.getTestResult());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class TestResultTest {

@Test
void equalsVerifier() throws Exception {
EntityUtils.equalsVerifier(TestResult.class);
EntityTestUtils.equalsVerifier(TestResult.class);

TestResult testResult1 = new TestResult();
testResult1.setId(1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private static void verifyRelationships(Message messages) {
}

@BeforeEach
void beforeEachSetup() throws ScenarioExecution.ErrorMessageTruncationException {
void beforeEachSetup() {
message = MessageResourceIT.createEntity(entityManager);

ScenarioExecution scenarioExecution = ScenarioExecutionResourceIT.createEntity(entityManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private static void verifyRelationships(ScenarioAction scenarioAction) {
}

@BeforeEach
void beforeEachSetup() throws ScenarioExecution.ErrorMessageTruncationException {
void beforeEachSetup() {
scenarioAction = createEntity(entityManager);

ScenarioExecution scenarioExecution = ScenarioExecutionResourceIT.createEntity(entityManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private static void verifyRelationships(ScenarioParameter scenarioParameter) {
}

@BeforeEach
void beforeEachSetup() throws ScenarioExecution.ErrorMessageTruncationException {
void beforeEachSetup() {
scenarioParameter = createEntity(entityManager);

ScenarioExecution scenarioExecution = ScenarioExecutionResourceIT.createEntity(entityManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ScenarioActionServiceImplTest {
private ScenarioActionServiceImpl fixture;

@BeforeEach
void beforeEachSetup() throws ScenarioExecution.ErrorMessageTruncationException {
void beforeEachSetup() {
ScenarioAction scenarioAction = new ScenarioAction();
ScenarioExecution scenarioExecution = ScenarioExecution.builder()
.startDate(Instant.now())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public class ScenarioExecutionResourceIT {
* This is a static method, as tests for other entities might also need it,
* if they test an entity which requires the current entity.
*/
public static ScenarioExecution createEntity(EntityManager entityManager) throws ScenarioExecution.ErrorMessageTruncationException {
public static ScenarioExecution createEntity(EntityManager entityManager) {
ScenarioExecution scenarioExecution = ScenarioExecution.builder()
.startDate(DEFAULT_START_DATE)
.endDate(DEFAULT_END_DATE)
Expand All @@ -85,7 +85,7 @@ public static ScenarioExecution createEntity(EntityManager entityManager) throws
* This is a static method, as tests for other entities might also need it,
* if they test an entity which requires the current entity.
*/
public static ScenarioExecution createUpdatedEntity(EntityManager entityManager) throws ScenarioExecution.ErrorMessageTruncationException {
public static ScenarioExecution createUpdatedEntity(EntityManager entityManager) {
ScenarioExecution scenarioExecution = ScenarioExecution.builder()
.startDate(UPDATED_START_DATE)
.endDate(UPDATED_END_DATE)
Expand All @@ -97,7 +97,7 @@ public static ScenarioExecution createUpdatedEntity(EntityManager entityManager)
}

@BeforeEach
void beforeEachSetup() throws ScenarioExecution.ErrorMessageTruncationException {
void beforeEachSetup() {
scenarioExecution = createEntity(entityManager);
}

Expand Down

0 comments on commit 45ea8f8

Please sign in to comment.