diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java index 6c5f518e1..d706e8fd5 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java @@ -193,6 +193,8 @@ public final class DateUtils { if (second == null) { return 1; } + first = first.withOffsetSameInstant(ZoneOffset.UTC); + second = second.withOffsetSameInstant(ZoneOffset.UTC); return truncate == null ? first.compareTo(second) : first.truncatedTo(truncate).compareTo(second.truncatedTo(truncate)); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java index 36d13697e..60f7aed1a 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java @@ -23,8 +23,10 @@ import static java.lang.String.format; import jakarta.validation.constraints.NotNull; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; @@ -251,18 +253,33 @@ public class DatabaseSpecificSQLGenerator { .collect(Collectors.joining(", ")); } - public String buildInsert(@NotNull String definition, Collection fields) { + public String buildInsert(@NotNull String definition, List fields, Map headers) { if (fields == null || fields.isEmpty()) { return ""; } return "INSERT INTO " + escape(definition) + '(' + fields.stream().map(this::escape).collect(Collectors.joining(", ")) - + ") VALUES (?" + ", ?".repeat(fields.size() - 1) + ')'; + + ") VALUES (" + fields.stream().map(e -> decoratePlaceHolder(headers, e, "?")).collect(Collectors.joining(", ")) + ')'; } - public String buildUpdate(@NotNull String definition, Collection fields) { + public String buildUpdate(@NotNull String definition, List fields, Map headers) { if (fields == null || fields.isEmpty()) { return ""; } - return "UPDATE " + escape(definition) + " SET " + fields.stream().map(e -> escape(e) + " = ?").collect(Collectors.joining(", ")); + return "UPDATE " + escape(definition) + " SET " + + fields.stream().map(e -> escape(e) + " = " + decoratePlaceHolder(headers, e, "?")).collect(Collectors.joining(", ")); + } + + private String decoratePlaceHolder(Map headers, String field, String placeHolder) { + DatabaseType dialect = getDialect(); + if (dialect.isPostgres()) { + ResultsetColumnHeaderData header = headers.get(field); + if (header != null) { + JdbcJavaType columnType = header.getColumnType(); + if (columnType.isJsonType()) { + return placeHolder + "::" + columnType.getJdbcName(dialect); + } + } + } + return placeHolder; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java index 929debb92..aea1339f6 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java @@ -74,6 +74,7 @@ public enum JdbcJavaType { TINYTEXT(JavaType.STRING, new DialectType(JDBCType.VARCHAR, "TINYTEXT"), new DialectType(JDBCType.VARCHAR, "TEXT")), // MEDIUMTEXT(JavaType.STRING, new DialectType(JDBCType.VARCHAR, "MEDIUMTEXT"), new DialectType(JDBCType.VARCHAR, "TEXT")), // LONGTEXT(JavaType.STRING, new DialectType(JDBCType.VARCHAR, "LONGTEXT"), new DialectType(JDBCType.VARCHAR, "TEXT")), // + JSON(JavaType.STRING, new DialectType(JDBCType.VARCHAR, "JSON"), new DialectType(JDBCType.VARCHAR, "JSON")), // DATE(JavaType.LOCAL_DATE, new DialectType(JDBCType.DATE), new DialectType(JDBCType.DATE)), // // precision for TIME, TIMESTAMP (postgres) and INTERVAL specifies the number of fractional digits retained in the // seconds field, but by default, there is no explicit bound on precision @@ -126,7 +127,7 @@ public enum JdbcJavaType { return javaType; } - public static JdbcJavaType getByTypeName(@NotNull DatabaseType dialect, String name) { + public static JdbcJavaType getByTypeName(@NotNull DatabaseType dialect, String name, boolean check) { if (name == null) { return null; } @@ -145,6 +146,10 @@ public enum JdbcJavaType { } } } + if (check) { + throw new PlatformServiceUnavailableException("error.msg.database.type.not.supported", + "Data type '" + name + "' is not supported "); + } return null; } @@ -179,7 +184,11 @@ public enum JdbcJavaType { } public boolean isTextType() { - return this == TEXT || this == TINYTEXT || this == MEDIUMTEXT || this == LONGTEXT; + return this == TEXT || this == TINYTEXT || this == MEDIUMTEXT || this == LONGTEXT || this == JSON; + } + + public boolean isJsonType() { + return this == JSON; } public boolean isSerialType() { @@ -262,7 +271,7 @@ public enum JdbcJavaType { public Object toJdbcValue(@NotNull DatabaseType dialect, Object value, boolean check) { if (value != null && check && !javaType.getObjectType().matchType(value.getClass(), false)) { - throw new PlatformServiceUnavailableException("error.msg.database.type.not.allowed", + throw new PlatformServiceUnavailableException("error.msg.database.type.not.valid", "Data type of parameter " + value + " does not match " + this); } return toJdbcValueImpl(dialect, value); diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java index a1b930807..a28c92a91 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/ResultsetColumnHeaderData.java @@ -75,7 +75,7 @@ public final class ResultsetColumnHeaderData implements Serializable { this.isColumnIndexed = columnIsIndexed; // Refer org.drizzle.jdbc.internal.mysql.MySQLType.java - this.columnType = JdbcJavaType.getByTypeName(dialect, adjustColumnType(columnType)); + this.columnType = JdbcJavaType.getByTypeName(dialect, adjustColumnType(columnType), true); this.columnDisplayType = calcDisplayType(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/DatatableCommandFromApiJsonDeserializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/DatatableCommandFromApiJsonDeserializer.java index 0d2d96da5..4e300bda4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/DatatableCommandFromApiJsonDeserializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/serialization/DatatableCommandFromApiJsonDeserializer.java @@ -23,6 +23,7 @@ import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaT import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaType.DATETIME; import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaType.DECIMAL; import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaType.INTEGER; +import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaType.JSON; import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaType.TEXT; import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaType.TIMESTAMP; import static org.apache.fineract.infrastructure.core.service.database.JdbcJavaType.VARCHAR; @@ -40,6 +41,7 @@ import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiCon import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant.API_FIELD_TYPE_DATETIME; import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant.API_FIELD_TYPE_DECIMAL; import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant.API_FIELD_TYPE_DROPDOWN; +import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant.API_FIELD_TYPE_JSON; import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant.API_FIELD_TYPE_NUMBER; import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant.API_FIELD_TYPE_STRING; import static org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant.API_FIELD_TYPE_TEXT; @@ -97,7 +99,8 @@ public class DatatableCommandFromApiJsonDeserializer { API_FIELD_MANDATORY, API_FIELD_AFTER, API_FIELD_CODE, API_FIELD_NEWCODE, API_FIELD_UNIQUE, API_FIELD_INDEXED); private static final Set SUPPORTED_PARAMETERS_FOR_DROP_COLUMNS = Set.of(API_FIELD_NAME); private static final Object[] SUPPORTED_COLUMN_TYPES = { API_FIELD_TYPE_STRING, API_FIELD_TYPE_NUMBER, API_FIELD_TYPE_BOOLEAN, - API_FIELD_TYPE_DECIMAL, API_FIELD_TYPE_DATE, API_FIELD_TYPE_DATETIME, API_FIELD_TYPE_TEXT, API_FIELD_TYPE_DROPDOWN }; + API_FIELD_TYPE_DECIMAL, API_FIELD_TYPE_DATE, API_FIELD_TYPE_DATETIME, API_FIELD_TYPE_TEXT, API_FIELD_TYPE_JSON, + API_FIELD_TYPE_DROPDOWN }; private final FromJsonHelper fromApiJsonHelper; private final DatabaseTypeResolver databaseTypeResolver; @@ -344,6 +347,8 @@ public class DatatableCommandFromApiJsonDeserializer { return TIMESTAMP; case API_FIELD_TYPE_TEXT: return TEXT; + case API_FIELD_TYPE_JSON: + return JSON; default: { if (fail) { throw new PlatformDataIntegrityException("error.msg.datatable.column.type.invalid", diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/DataTableApiConstant.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/DataTableApiConstant.java index 0028c2070..85bb7fb8e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/DataTableApiConstant.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/DataTableApiConstant.java @@ -85,5 +85,6 @@ public final class DataTableApiConstant { public static final String API_FIELD_TYPE_DATETIME = "datetime"; public static final String API_FIELD_TYPE_TIMESTAMP = "timestamp"; public static final String API_FIELD_TYPE_TEXT = "text"; + public static final String API_FIELD_TYPE_JSON = "json"; public static final String API_FIELD_TYPE_DROPDOWN = "dropdown"; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/GenericDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/GenericDataServiceImpl.java index 50722954c..9e58f044f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/GenericDataServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/GenericDataServiceImpl.java @@ -117,7 +117,7 @@ public class GenericDataServiceImpl implements GenericDataService { // primary keys and unique constrained columns are automatically indexed final boolean columnIsIndexed = columnIsPrimaryKey || columnIsUnique || isExplicitlyIndexed(tableName, columnName, indexDefinitions); - JdbcJavaType jdbcType = JdbcJavaType.getByTypeName(dialect, columnType); + JdbcJavaType jdbcType = JdbcJavaType.getByTypeName(dialect, columnType, false); List columnValues = new ArrayList<>(); String codeName = null; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java index 37d63686e..205fdfef7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java @@ -1323,7 +1323,6 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ params.add(SearchUtil.parseJdbcColumnValue(columnHeader, dataParams.get(key), dateFormat, dateTimeFormat, locale, false, sqlGenerator)); } - final String sql = sqlGenerator.buildInsert(dataTableName, insertColumns); if (addScore) { List scoreIds = params.stream().filter(e -> e != null && !String.valueOf(e).isBlank()).toList(); int scoreValue; @@ -1339,6 +1338,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ insertColumns.add("score"); params.add(scoreValue); } + + final String sql = sqlGenerator.buildInsert(dataTableName, insertColumns, headersByName); try { int updated = jdbcTemplate.update(sql, params.toArray(Object[]::new)); if (updated != 1) { @@ -1446,8 +1447,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ Locale locale = localeString == null ? null : JsonParserHelper.localeFromString(localeString); DatabaseType dialect = sqlGenerator.getDialect(); - List updateColumns = new ArrayList<>(List.of(UPDATEDAT_FIELD_NAME)); - List params = new ArrayList<>(List.of(DateUtils.getAuditLocalDateTime())); + ArrayList updateColumns = new ArrayList<>(List.of(UPDATEDAT_FIELD_NAME)); + ArrayList params = new ArrayList<>(List.of(DateUtils.getAuditLocalDateTime())); final HashMap changes = new HashMap<>(); for (String key : dataParams.keySet()) { if (isTechnicalParam(key)) { @@ -1474,7 +1475,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ if (!updateColumns.isEmpty()) { ResultsetColumnHeaderData pkColumn = SearchUtil.getFiltered(columnHeaders, ResultsetColumnHeaderData::getIsColumnPrimaryKey); params.add(primaryKey); - final String sql = sqlGenerator.buildUpdate(dataTableName, updateColumns) + " WHERE " + pkColumn.getColumnName() + " = ?"; + final String sql = sqlGenerator.buildUpdate(dataTableName, updateColumns, headersByName) + " WHERE " + pkColumn.getColumnName() + + " = ?"; int updated = jdbcTemplate.update(sql, params.toArray(Object[]::new)); if (updated != 1) { throw new PlatformDataIntegrityException("error.msg.invalid.update", "Expected one updated row."); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientAuditingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientAuditingIntegrationTest.java index 15d41a937..d66990803 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientAuditingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientAuditingIntegrationTest.java @@ -23,6 +23,7 @@ import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsCons import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY; import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; @@ -30,9 +31,10 @@ import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.time.OffsetDateTime; -import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.Map; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.organisation.StaffHelper; @@ -65,12 +67,7 @@ public class ClientAuditingIntegrationTest { String username = Utils.uniqueRandomStringGenerator("user", 8); final Integer userId = (Integer) UserHelper.createUser(this.requestSpec, this.responseSpec, 1, staffId, username, "password", "resourceId"); - OffsetDateTime now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); - // Testing in minutes precision, but still need to take care around the end of the actual minute - if (now.getSecond() > 56) { - Thread.sleep(5000); - now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); - } + OffsetDateTime now = Utils.getAuditDateTimeToCompare(); LOG.info("-------------------------Creating Client---------------------------"); final Integer clientID = ClientHelper.createClientPending(requestSpec, responseSpec); @@ -79,55 +76,36 @@ public class ClientAuditingIntegrationTest { OffsetDateTime createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); - OffsetDateTime lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); LOG.info("-------------------------Check Audit dates---------------------------"); assertEquals(1, auditFieldsResponse.get(CREATED_BY)); assertEquals(1, auditFieldsResponse.get(LAST_MODIFIED_BY)); - assertEquals(now.getYear(), createdDate.getYear()); - assertEquals(now.getMonth(), createdDate.getMonth()); - assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth()); - assertEquals(now.getHour(), createdDate.getHour()); - assertEquals(now.getMinute(), createdDate.getMinute()); - - assertEquals(now.getYear(), lastModifiedDate.getYear()); - assertEquals(now.getMonth(), lastModifiedDate.getMonth()); - assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth()); - assertEquals(now.getHour(), lastModifiedDate.getHour()); - assertEquals(now.getMinute(), lastModifiedDate.getMinute()); + assertTrue(DateUtils.isEqual(now, createdDate, ChronoUnit.MINUTES)); + assertTrue(DateUtils.isEqual(now, lastModifiedDate, ChronoUnit.MINUTES)); LOG.info("-------------------------Modify Client with System user---------------------------"); this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, "password")); - this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec); + + OffsetDateTime now2 = Utils.getAuditDateTimeToCompare(); this.clientHelper.activateClient(clientID); auditFieldsResponse = ClientHelper.getClientAuditFields(requestSpec, responseSpec, clientID, ""); - createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); - + OffsetDateTime createdDate2 = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), + DateTimeFormatter.ISO_OFFSET_DATE_TIME); lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); LOG.info("-------------------------Check Audit dates---------------------------"); assertEquals(1, auditFieldsResponse.get(CREATED_BY)); - assertEquals(now.getYear(), createdDate.getYear()); - assertEquals(now.getMonth(), createdDate.getMonth()); - assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth()); - assertEquals(now.getHour(), createdDate.getHour()); - assertEquals(now.getMinute(), createdDate.getMinute()); - - now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); + assertTrue(DateUtils.isEqual(now, createdDate2, ChronoUnit.MINUTES)); + assertTrue(DateUtils.isEqual(createdDate, createdDate2)); assertEquals(userId, auditFieldsResponse.get(LAST_MODIFIED_BY)); - assertEquals(now.getYear(), lastModifiedDate.getYear()); - assertEquals(now.getMonth(), lastModifiedDate.getMonth()); - assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth()); - assertEquals(now.getHour(), lastModifiedDate.getHour()); - assertEquals(now.getMinute(), lastModifiedDate.getMinute()); + assertTrue(DateUtils.isEqual(now2, lastModifiedDate, ChronoUnit.MINUTES)); } - } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java index 318ec3774..f36d51827 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java @@ -23,6 +23,7 @@ import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsCons import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY; import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; @@ -30,12 +31,13 @@ import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.time.OffsetDateTime; -import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; @@ -93,12 +95,8 @@ public class LoanAuditingIntegrationTest { final Integer loanProductID = createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, "2", assetAccount, incomeAccount, expenseAccount, overpaymentAccount); - OffsetDateTime now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); - // Testing in minutes precision, but still need to take care around the end of the actual minute - if (now.getSecond() > 56) { - Thread.sleep(5000); - now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); - } + OffsetDateTime now = Utils.getAuditDateTimeToCompare(); + final Integer loanID = applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID, Collections.emptyList(), null, "10000", LoanApplicationTestBuilder.DEFAULT_STRATEGY, "10 July 2022"); Assertions.assertNotNull(loanID); @@ -109,57 +107,39 @@ public class LoanAuditingIntegrationTest { OffsetDateTime createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); - OffsetDateTime lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); LOG.info("-------------------------Check Audit dates---------------------------"); assertEquals(1, auditFieldsResponse.get(CREATED_BY)); assertEquals(1, auditFieldsResponse.get(LAST_MODIFIED_BY)); - assertEquals(now.getYear(), createdDate.getYear()); - assertEquals(now.getMonth(), createdDate.getMonth()); - assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth()); - assertEquals(now.getHour(), createdDate.getHour()); - assertEquals(now.getMinute(), createdDate.getMinute()); - - assertEquals(now.getYear(), lastModifiedDate.getYear()); - assertEquals(now.getMonth(), lastModifiedDate.getMonth()); - assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth()); - assertEquals(now.getHour(), lastModifiedDate.getHour()); - assertEquals(now.getMinute(), lastModifiedDate.getMinute()); + assertTrue(DateUtils.isEqual(now, createdDate, ChronoUnit.MINUTES)); + assertTrue(DateUtils.isEqual(now, lastModifiedDate, ChronoUnit.MINUTES)); LOG.info("-----------------------------------APPROVE LOAN-----------------------------------------"); this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, "P4ssw0rd")); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + + OffsetDateTime now2 = Utils.getAuditDateTimeToCompare(); loanStatusHashMap = this.loanTransactionHelper.approveLoan("11 July 2022", loanID); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); auditFieldsResponse = LoanTransactionHelper.getLoanAuditFields(requestSpec, responseSpec, loanID, ""); - createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); - + OffsetDateTime createdDate2 = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), + DateTimeFormatter.ISO_OFFSET_DATE_TIME); lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); LOG.info("-------------------------Check Audit dates---------------------------"); assertEquals(1, auditFieldsResponse.get(CREATED_BY)); - assertEquals(now.getYear(), createdDate.getYear()); - assertEquals(now.getMonth(), createdDate.getMonth()); - assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth()); - assertEquals(now.getHour(), createdDate.getHour()); - assertEquals(now.getMinute(), createdDate.getMinute()); - - now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); + assertTrue(DateUtils.isEqual(now, createdDate2, ChronoUnit.MINUTES)); + assertTrue(DateUtils.isEqual(createdDate, createdDate2)); assertEquals(userId, auditFieldsResponse.get(LAST_MODIFIED_BY)); - assertEquals(now.getYear(), lastModifiedDate.getYear()); - assertEquals(now.getMonth(), lastModifiedDate.getMonth()); - assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth()); - assertEquals(now.getHour(), lastModifiedDate.getHour()); - assertEquals(now.getMinute(), lastModifiedDate.getMinute()); + assertTrue(DateUtils.isEqual(now2, lastModifiedDate, ChronoUnit.MINUTES)); } private Integer applyForLoanApplicationWithPaymentStrategyAndPastMonth(final Integer clientID, final Integer loanProductID, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java index aadabadee..c1a4e5f47 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java @@ -23,6 +23,7 @@ import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsCons import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY; import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; @@ -30,11 +31,12 @@ import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.time.OffsetDateTime; -import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.HashMap; import java.util.List; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; @@ -105,12 +107,7 @@ public class LoanTransactionAuditingIntegrationTest { loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("11 July 2022", loanID, "10000"); LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); - OffsetDateTime now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); - // Testing in minutes precision, but still need to take care around the end of the actual minute - if (now.getSecond() > 56) { - Thread.sleep(5000); - now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); - } + OffsetDateTime now = Utils.getAuditDateTimeToCompare(); HashMap repaymentDetails = this.loanTransactionHelper.makeRepayment("11 July 2022", 100.0f, loanID); Integer transactionId = (Integer) repaymentDetails.get("resourceId"); HashMap auditFieldsResponse = LoanTransactionHelper.getLoanTransactionAuditFields(requestSpec, responseSpec, loanID, transactionId, @@ -118,59 +115,39 @@ public class LoanTransactionAuditingIntegrationTest { OffsetDateTime createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); - OffsetDateTime lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); LOG.info("-------------------------Check Audit dates---------------------------"); assertEquals(1, auditFieldsResponse.get(CREATED_BY)); - assertEquals(now.getYear(), createdDate.getYear()); - assertEquals(now.getMonth(), createdDate.getMonth()); - assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth()); - assertEquals(now.getHour(), createdDate.getHour()); - assertEquals(now.getMinute(), createdDate.getMinute()); - assertEquals(1, auditFieldsResponse.get(LAST_MODIFIED_BY)); - assertEquals(now.getYear(), lastModifiedDate.getYear()); - assertEquals(now.getMonth(), lastModifiedDate.getMonth()); - assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth()); - assertEquals(now.getHour(), lastModifiedDate.getHour()); - assertEquals(now.getMinute(), lastModifiedDate.getMinute()); + assertTrue(DateUtils.isEqual(now, createdDate, ChronoUnit.MINUTES)); + assertTrue(DateUtils.isEqual(now, lastModifiedDate, ChronoUnit.MINUTES)); Thread.sleep(2000); this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, "P4ssw0rd")); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - this.loanTransactionHelper.reverseRepayment(loanID, transactionId, "11 July 2022"); - now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); + OffsetDateTime now2 = Utils.getAuditDateTimeToCompare(); + this.loanTransactionHelper.reverseRepayment(loanID, transactionId, "11 July 2022"); auditFieldsResponse = LoanTransactionHelper.getLoanTransactionAuditFields(requestSpec, responseSpec, loanID, transactionId, ""); - createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); - + OffsetDateTime createdDate2 = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), + DateTimeFormatter.ISO_OFFSET_DATE_TIME); lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME); LOG.info("-------------------------Check Audit dates---------------------------"); assertEquals(1, auditFieldsResponse.get(CREATED_BY)); - assertEquals(now.getYear(), createdDate.getYear()); - assertEquals(now.getMonth(), createdDate.getMonth()); - assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth()); - assertEquals(now.getHour(), createdDate.getHour()); - assertEquals(now.getMinute(), createdDate.getMinute()); - - now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata")); + assertTrue(DateUtils.isEqual(now, createdDate2, ChronoUnit.MINUTES)); + assertTrue(DateUtils.isEqual(createdDate, createdDate2)); assertEquals(userId, auditFieldsResponse.get(LAST_MODIFIED_BY)); - assertEquals(now.getYear(), lastModifiedDate.getYear()); - assertEquals(now.getMonth(), lastModifiedDate.getMonth()); - assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth()); - assertEquals(now.getHour(), lastModifiedDate.getHour()); - assertEquals(now.getMinute(), lastModifiedDate.getMinute()); + assertTrue(DateUtils.isEqual(now2, lastModifiedDate, ChronoUnit.MINUTES)); } private Integer applyForLoanApplicationWithPaymentStrategyAndPastMonth(final Integer clientID, final Integer loanProductID, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java index b9738cf73..5fc131b0e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java @@ -44,7 +44,6 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; @@ -63,7 +62,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Supplier; import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.http.conn.HttpHostConnectException; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -376,12 +377,15 @@ public final class Utils { return dateFormat.format(dateToBeConvert.getTime()); } - public static OffsetDateTime getAuditOffsetDateTime() { - return OffsetDateTime.now(ZoneOffset.UTC); - } - - public static LocalDateTime getLocalDateTimeOfSystem() { - return LocalDateTime.now(ZoneId.systemDefault()); + @NotNull + public static OffsetDateTime getAuditDateTimeToCompare() throws InterruptedException { + OffsetDateTime now = DateUtils.getAuditOffsetDateTime(); + // Testing in minutes precision, but still need to take care around the end of the actual minute + if (now.getSecond() > 56) { + Thread.sleep(5000); + now = DateUtils.getAuditOffsetDateTime(); + } + return now; } public static TimeZone getTimeZoneOfTenant() { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java index 2c7b8a4bc..3c9bdc4f7 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java @@ -139,6 +139,7 @@ public class DatatableIntegrationTest extends IntegrationTest { String itsANumber = "itsanumber"; String itsAString = "itsastring"; String itsAText = "itsatext"; + String itsAJson = "itsajson"; String tst_tst_tst_cd_itsADropdown = tst_tst_tst + "_cd_itsadropdown"; String dateFormat = "dateFormat"; @@ -155,43 +156,45 @@ public class DatatableIntegrationTest extends IntegrationTest { columnMap.put("apptableName", null); String errorRequestJsonString = new Gson().toJson(columnMap); ResponseSpecification responseSpecError400 = new ResponseSpecBuilder().expectStatusCode(400).build(); - this.datatableHelper = new DatatableHelper(this.requestSpec, responseSpecError400); - HashMap errorResponse = this.datatableHelper.createDatatable(errorRequestJsonString, ""); + DatatableHelper error400Helper = new DatatableHelper(this.requestSpec, responseSpecError400); + HashMap errorResponse = error400Helper.createDatatable(errorRequestJsonString, ""); assertEquals("validation.msg.validation.errors.exist", ((Map) errorResponse).get("userMessageGlobalisationCode")); List errors = (List) ((Map) errorResponse).get("errors"); assertEquals(2, errors.size()); assertEquals("validation.msg.datatable.apptableName.cannot.be.blank", ((Map) errors.get(0)).get("userMessageGlobalisationCode")); assertEquals("validation.msg.datatable.apptableName.is.not.one.of.expected.enumerations", ((Map) errors.get(1)).get("userMessageGlobalisationCode")); + // set valid apptable name columnMap.put("apptableName", CLIENT_APP_TABLE_NAME); // try to create datatable with invalid column type HashMap textColumn = addDatatableColumn(datatableColumnsList, itsAText, "Invalid", true, null, null); errorRequestJsonString = new Gson().toJson(columnMap); - errorResponse = this.datatableHelper.createDatatable(errorRequestJsonString, ""); + errorResponse = error400Helper.createDatatable(errorRequestJsonString, ""); assertEquals("validation.msg.validation.errors.exist", ((Map) errorResponse).get("userMessageGlobalisationCode")); errors = (List) ((Map) errorResponse).get("errors"); assertEquals(1, errors.size()); Map error = (Map) errors.get(0); assertEquals("validation.msg.datatable.type.is.not.one.of.expected.enumerations", error.get("userMessageGlobalisationCode")); - assertTrue(((String) error.get("defaultUserMessage")).contains("string, number, boolean, decimal, date, datetime, text, dropdown")); + assertTrue(((String) error.get("defaultUserMessage")) + .contains("string, number, boolean, decimal, date, datetime, text, json, dropdown")); + // set valid type textColumn.put("type", "Text"); + // add json type + addDatatableColumn(datatableColumnsList, itsAJson, "Json", false, null, null); String datatabelRequestJsonString = new Gson().toJson(columnMap); LOG.info("map : {}", datatabelRequestJsonString); - this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec); HashMap datatableResponse = this.datatableHelper.createDatatable(datatabelRequestJsonString, ""); String datatableName = (String) datatableResponse.get("resourceIdentifier"); DatatableHelper.verifyDatatableCreatedOnServer(this.requestSpec, this.responseSpec, datatableName); // try to create with the same name - this.datatableHelper = new DatatableHelper(this.requestSpec, responseSpecError400); - errorResponse = this.datatableHelper.createDatatable(datatabelRequestJsonString, ""); + errorResponse = error400Helper.createDatatable(datatabelRequestJsonString, ""); assertEquals("validation.msg.validation.errors.exist", ((Map) errorResponse).get("userMessageGlobalisationCode")); - this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec); // creating client with datatables final Integer clientID = ClientHelper.createClientAsPerson(requestSpec, responseSpec); @@ -211,7 +214,19 @@ public class DatatableIntegrationTest extends IntegrationTest { datatableEntryMap.put("locale", "en"); datatableEntryMap.put(dateFormat, "yyyy-MM-dd"); + String json = "{\"testparam\": \"testvalue\"}"; + // add invalid json + datatableEntryMap.put(itsAJson, '{' + json); + String datatabelEntryRequestJsonString = new Gson().toJson(datatableEntryMap); + ResponseSpecification responseSpecError403 = new ResponseSpecBuilder().expectStatusCode(403).build(); + DatatableHelper error403Helper = new DatatableHelper(this.requestSpec, responseSpecError403); + errorResponse = error403Helper.createDatatableEntry(datatableName, clientID, genericResultSet, datatabelEntryRequestJsonString); + + // add valid json + datatableEntryMap.put(itsAJson, json); + + datatabelEntryRequestJsonString = new Gson().toJson(datatableEntryMap); LOG.info("map : {}", datatabelEntryRequestJsonString); HashMap datatableEntryResponse = this.datatableHelper.createDatatableEntry(datatableName, clientID, @@ -222,37 +237,43 @@ public class DatatableIntegrationTest extends IntegrationTest { final HashMap items = this.datatableHelper.readDatatableEntry(datatableName, clientID, genericResultSet, (Integer) datatableEntryResponse.get("resourceId"), ""); assertNotNull(items); - assertEquals(1, ((List) items.get("data")).size()); - assertEquals("client_id", ((Map) ((List) items.get("columnHeaders")).get(0)).get("columnName")); - assertEquals(clientID, ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(0)); + List columnHeaders = (List) items.get("columnHeaders"); + List columnData = (List) items.get("data"); + assertEquals(1, columnData.size()); - assertEquals(itsABoolean, ((Map) ((List) items.get("columnHeaders")).get(1)).get("columnName")); - assertEquals(datatableEntryMap.get(itsABoolean), ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(1)); + Map data = (Map) columnData.get(0); - assertEquals(itsADate, ((Map) ((List) items.get("columnHeaders")).get(2)).get("columnName")); - assertEquals(datatableEntryMap.get(itsADate), - Utils.arrayDateToString((List) ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(2))); + assertEquals("client_id", ((Map) columnHeaders.get(0)).get("columnName")); + assertEquals(clientID, ((List) data.get("row")).get(0)); - assertEquals(itsADatetime, ((Map) ((List) items.get("columnHeaders")).get(3)).get("columnName")); - assertEquals(datatableEntryMap.get(itsADatetime), - Utils.arrayDateTimeToString((List) ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(3))); + assertEquals(itsABoolean, ((Map) columnHeaders.get(1)).get("columnName")); + assertEquals(datatableEntryMap.get(itsABoolean), ((List) data.get("row")).get(1)); - assertEquals(itsADecimal, ((Map) ((List) items.get("columnHeaders")).get(4)).get("columnName")); - assertEquals(datatableEntryMap.get(itsADecimal), ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(4)); + assertEquals(itsADate, ((Map) columnHeaders.get(2)).get("columnName")); + assertEquals(datatableEntryMap.get(itsADate), Utils.arrayDateToString((List) ((List) data.get("row")).get(2))); - assertEquals(tst_tst_tst_cd_itsADropdown, ((Map) ((List) items.get("columnHeaders")).get(5)).get("columnName")); - assertEquals(datatableEntryMap.get(tst_tst_tst_cd_itsADropdown), - ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(5)); + assertEquals(itsADatetime, ((Map) columnHeaders.get(3)).get("columnName")); + assertEquals(datatableEntryMap.get(itsADatetime), Utils.arrayDateTimeToString((List) ((List) data.get("row")).get(3))); - assertEquals(itsANumber, ((Map) ((List) items.get("columnHeaders")).get(6)).get("columnName")); - assertEquals(datatableEntryMap.get(itsANumber), ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(6)); + assertEquals(itsADecimal, ((Map) columnHeaders.get(4)).get("columnName")); + assertEquals(datatableEntryMap.get(itsADecimal), ((List) data.get("row")).get(4)); - assertEquals(itsAString, ((Map) ((List) items.get("columnHeaders")).get(7)).get("columnName")); - assertEquals(datatableEntryMap.get(itsAString), ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(7)); + assertEquals(tst_tst_tst_cd_itsADropdown, ((Map) columnHeaders.get(5)).get("columnName")); + assertEquals(datatableEntryMap.get(tst_tst_tst_cd_itsADropdown), ((List) data.get("row")).get(5)); - assertEquals(itsAText, ((Map) ((List) items.get("columnHeaders")).get(8)).get("columnName")); - assertEquals(datatableEntryMap.get(itsAText), ((List) ((Map) ((List) items.get("data")).get(0)).get("row")).get(8)); + assertEquals(itsANumber, ((Map) columnHeaders.get(6)).get("columnName")); + assertEquals(datatableEntryMap.get(itsANumber), ((List) data.get("row")).get(6)); + + assertEquals(itsAString, ((Map) columnHeaders.get(7)).get("columnName")); + assertEquals(datatableEntryMap.get(itsAString), ((List) data.get("row")).get(7)); + + assertEquals(itsAText, ((Map) columnHeaders.get(8)).get("columnName")); + assertEquals(datatableEntryMap.get(itsAText), ((List) data.get("row")).get(8)); + + assertEquals(itsAJson, ((Map) columnHeaders.get(9)).get("columnName")); + Object jsonResponse = ((List) data.get("row")).get(9); + assertEquals(datatableEntryMap.get(itsAJson), jsonResponse instanceof Map ? ((Map) jsonResponse).get("value") : jsonResponse); // Read the Datatable entry generated with genericResultSet in false List> datatableEntryResponseNoGenericResult = this.datatableHelper.readDatatableEntry(datatableName, @@ -260,19 +281,17 @@ public class DatatableIntegrationTest extends IntegrationTest { assertNotNull(datatableEntryResponseNoGenericResult, "ERROR IN GETTING THE DATE VALUE FROM DATATABLE RECORD"); assertEquals(1, datatableEntryResponseNoGenericResult.size()); - assertEquals(clientID, datatableEntryResponseNoGenericResult.get(0).get("client_id")); - assertEquals(datatableEntryMap.get(itsABoolean), - Boolean.valueOf((String) datatableEntryResponseNoGenericResult.get(0).get(itsABoolean))); - assertEquals(datatableEntryMap.get(itsADate), - Utils.arrayDateToString((List) datatableEntryResponseNoGenericResult.get(0).get(itsADate))); - assertEquals(datatableEntryMap.get(itsADecimal), datatableEntryResponseNoGenericResult.get(0).get(itsADecimal)); - assertEquals(datatableEntryMap.get(itsADatetime), - Utils.arrayDateTimeToString((List) datatableEntryResponseNoGenericResult.get(0).get(itsADatetime))); - assertEquals(datatableEntryMap.get(tst_tst_tst_cd_itsADropdown), - datatableEntryResponseNoGenericResult.get(0).get(tst_tst_tst_cd_itsADropdown)); - assertEquals(datatableEntryMap.get(itsANumber), datatableEntryResponseNoGenericResult.get(0).get(itsANumber)); - assertEquals(datatableEntryMap.get(itsAString), datatableEntryResponseNoGenericResult.get(0).get(itsAString)); - assertEquals(datatableEntryMap.get(itsAText), datatableEntryResponseNoGenericResult.get(0).get(itsAText)); + HashMap responseMap = datatableEntryResponseNoGenericResult.get(0); + assertEquals(clientID, responseMap.get("client_id")); + assertEquals(datatableEntryMap.get(itsABoolean), Boolean.valueOf((String) responseMap.get(itsABoolean))); + assertEquals(datatableEntryMap.get(itsADate), Utils.arrayDateToString((List) responseMap.get(itsADate))); + assertEquals(datatableEntryMap.get(itsADecimal), responseMap.get(itsADecimal)); + assertEquals(datatableEntryMap.get(itsADatetime), Utils.arrayDateTimeToString((List) responseMap.get(itsADatetime))); + assertEquals(datatableEntryMap.get(tst_tst_tst_cd_itsADropdown), responseMap.get(tst_tst_tst_cd_itsADropdown)); + assertEquals(datatableEntryMap.get(itsANumber), responseMap.get(itsANumber)); + assertEquals(datatableEntryMap.get(itsAString), responseMap.get(itsAString)); + assertEquals(datatableEntryMap.get(itsAText), responseMap.get(itsAText)); + assertEquals(datatableEntryMap.get(itsAJson), responseMap.get(itsAJson)); // Update datatable entry Boolean previousBoolean = (Boolean) datatableEntryMap.get(itsABoolean); @@ -475,10 +494,9 @@ public class DatatableIntegrationTest extends IntegrationTest { // try to create with the same name ResponseSpecification responseSpecError400 = new ResponseSpecBuilder().expectStatusCode(400).build(); - this.datatableHelper = new DatatableHelper(this.requestSpec, responseSpecError400); - HashMap response = this.datatableHelper.createDatatable(datatabelRequestJsonString, ""); + DatatableHelper error400Helper = new DatatableHelper(this.requestSpec, responseSpecError400); + HashMap response = error400Helper.createDatatable(datatabelRequestJsonString, ""); assertEquals("validation.msg.validation.errors.exist", ((Map) response).get("userMessageGlobalisationCode")); - this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec); // creating client with datatables final Integer clientID = ClientHelper.createClientAsPerson(requestSpec, responseSpec); @@ -739,10 +757,9 @@ public class DatatableIntegrationTest extends IntegrationTest { // try to create with the same name ResponseSpecification responseSpecError400 = new ResponseSpecBuilder().expectStatusCode(400).build(); - this.datatableHelper = new DatatableHelper(this.requestSpec, responseSpecError400); - HashMap response = this.datatableHelper.createDatatable(datatabelRequestJsonString, ""); + DatatableHelper error400Helper = new DatatableHelper(this.requestSpec, responseSpecError400); + HashMap response = error400Helper.createDatatable(datatabelRequestJsonString, ""); assertEquals("validation.msg.validation.errors.exist", ((Map) response).get("userMessageGlobalisationCode")); - this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec); // creating client with datatables final Integer clientID = ClientHelper.createClientAsPerson(requestSpec, responseSpec);