chore: Oracle: add JUnit TCs (#22788)
## Description - Add JUnit TCs - Minor improvement to reading of data types: `timestamp`, `raw`, `blob` Fixes #20535
This commit is contained in:
parent
aa7ef11aa1
commit
09fd519e2c
|
|
@ -1,11 +1,14 @@
|
|||
package com.appsmith.external.helpers;
|
||||
|
||||
import com.appsmith.external.constants.ConditionalOperator;
|
||||
import com.appsmith.external.datatypes.ClientDataType;
|
||||
import com.appsmith.external.dtos.ExecuteActionDTO;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
|
||||
import com.appsmith.external.models.Condition;
|
||||
import com.appsmith.external.models.DatasourceConfiguration;
|
||||
import com.appsmith.external.models.Endpoint;
|
||||
import com.appsmith.external.models.Param;
|
||||
import com.appsmith.external.models.Property;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
|
@ -25,6 +28,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
|
@ -236,7 +240,7 @@ public class PluginUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void setDataValueSafelyInFormData(Map<String, Object> formData, String field, Object value) {
|
||||
public static Map setDataValueSafelyInFormData(Map<String, Object> formData, String field, Object value) {
|
||||
|
||||
// In case the formData has not been initialized before the fxn call, assign a new HashMap to the variable
|
||||
if (formData == null) {
|
||||
|
|
@ -269,9 +273,11 @@ public class PluginUtils {
|
|||
formData.put(field, valueMap);
|
||||
}
|
||||
}
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
public static void setValueSafelyInFormData(Map<String, Object> formData, String field, Object value) {
|
||||
public static Map setValueSafelyInFormData(Map<String, Object> formData, String field, Object value) {
|
||||
|
||||
// In case the formData has not been initialized before the fxn call, assign a new HashMap to the variable
|
||||
if (formData == null) {
|
||||
|
|
@ -297,6 +303,8 @@ public class PluginUtils {
|
|||
// This is a top level field. Set the value
|
||||
formData.put(field, value);
|
||||
}
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
public static boolean endpointContainsLocalhost(Endpoint endpoint) {
|
||||
|
|
@ -464,4 +472,22 @@ public class PluginUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ExecuteActionDTO getExecuteDTOForTestWithBindingAndValueAndDataType(LinkedHashMap<String, List> bindingValueDataTypeMap) {
|
||||
List<Param> params = new ArrayList<>();
|
||||
bindingValueDataTypeMap.keySet().stream()
|
||||
.forEach(bindingName -> {
|
||||
String bindingValue = (String) (bindingValueDataTypeMap.get(bindingName)).get(0);
|
||||
ClientDataType clientDataType = (ClientDataType) (bindingValueDataTypeMap.get(bindingName)).get(1);
|
||||
Param param = new Param();
|
||||
param.setKey(bindingName);
|
||||
param.setValue(bindingValue);
|
||||
param.setClientDataType(clientDataType);
|
||||
params.add(param);
|
||||
});
|
||||
|
||||
ExecuteActionDTO executeActionDTO = new ExecuteActionDTO();
|
||||
executeActionDTO.setParams(params);
|
||||
return executeActionDTO;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,25 +34,20 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Dependencies -->
|
||||
<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 -->
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
<version>21.9.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>oracle-xe</artifactId>
|
||||
<version>1.17.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Dependencies -->
|
||||
<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 -->
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>jdbc-test</artifactId>
|
||||
<version>1.11.4</version>
|
||||
</dependency>
|
||||
<artifactId>oracle-xe</artifactId>
|
||||
<version>1.18.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -115,13 +115,18 @@ public class OraclePlugin extends BasePlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Mono<ActionExecutionResult> execute(HikariDataSource connection, DatasourceConfiguration datasourceConfiguration, ActionConfiguration actionConfiguration) {
|
||||
public Mono<ActionExecutionResult> execute(HikariDataSource connection,
|
||||
DatasourceConfiguration datasourceConfiguration,
|
||||
ActionConfiguration actionConfiguration) {
|
||||
return Mono.error(
|
||||
new AppsmithPluginException(OraclePluginError.QUERY_EXECUTION_FAILED, "Unsupported Operation"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ActionExecutionResult> executeParameterized(HikariDataSource connection, ExecuteActionDTO executeActionDTO, DatasourceConfiguration datasourceConfiguration, ActionConfiguration actionConfiguration) {
|
||||
public Mono<ActionExecutionResult> executeParameterized(HikariDataSource connectionPool,
|
||||
ExecuteActionDTO executeActionDTO,
|
||||
DatasourceConfiguration datasourceConfiguration,
|
||||
ActionConfiguration actionConfiguration) {
|
||||
final Map<String, Object> formData = actionConfiguration.getFormData();
|
||||
String query = getDataValueSafelyFromFormData(formData, BODY, STRING_TYPE, null);
|
||||
// Check for query parameter before performing the probably expensive fetch connection from the pool op.
|
||||
|
|
@ -144,7 +149,7 @@ public class OraclePlugin extends BasePlugin {
|
|||
// In case of non-prepared statement, simply do binding-replacement and execute
|
||||
if (FALSE.equals(isPreparedStatement)) {
|
||||
prepareConfigurationsForExecution(executeActionDTO, actionConfiguration, datasourceConfiguration);
|
||||
return executeCommon(connection, datasourceConfiguration, actionConfiguration, FALSE, null, null);
|
||||
return executeCommon(connectionPool, datasourceConfiguration, actionConfiguration, FALSE, null, null);
|
||||
}
|
||||
|
||||
// First extract all the bindings in order
|
||||
|
|
@ -162,7 +167,7 @@ public class OraclePlugin extends BasePlugin {
|
|||
updatedQuery = removeSemicolonFromQuery(updatedQuery);
|
||||
}
|
||||
setDataValueSafelyInFormData(formData, BODY, updatedQuery);
|
||||
return executeCommon(connection, datasourceConfiguration, actionConfiguration, TRUE,
|
||||
return executeCommon(connectionPool, datasourceConfiguration, actionConfiguration, TRUE,
|
||||
mustacheKeysInOrder, executeActionDTO);
|
||||
}
|
||||
|
||||
|
|
@ -288,8 +293,9 @@ public class OraclePlugin extends BasePlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Mono<DatasourceStructure> getStructure(HikariDataSource connection, DatasourceConfiguration datasourceConfiguration) {
|
||||
return OracleDatasourceUtils.getStructure(connection, datasourceConfiguration);
|
||||
public Mono<DatasourceStructure> getStructure(HikariDataSource connectionPool,
|
||||
DatasourceConfiguration datasourceConfiguration) {
|
||||
return OracleDatasourceUtils.getStructure(connectionPool, datasourceConfiguration);
|
||||
}
|
||||
|
||||
private Set<String> populateHintMessages(List<String> columnNames) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ public class OracleErrorMessages {
|
|||
|
||||
public static final String INVALID_SSL_OPTION_ERROR_MSG = "The Appsmith server has found an unexpected SSL option: %s.";
|
||||
|
||||
public static final String CONNECTION_POOL_CREATION_FAILED_ERROR_MSG = "An exception occurred while creating connection pool. One or more arguments in the datasource configuration may be invalid.";
|
||||
public static final String CONNECTION_POOL_CREATION_FAILED_ERROR_MSG = "An exception occurred while creating " +
|
||||
"connection pool. One or more arguments in the datasource configuration may be invalid.";
|
||||
|
||||
/*
|
||||
************************************************************************************************************************************************
|
||||
|
|
|
|||
|
|
@ -307,10 +307,10 @@ public class OracleDatasourceUtils {
|
|||
getSampleColumnNamesCSVString(columnNameToSampleColumnDataMap),
|
||||
getSampleColumnDataCSVString(columnNameToSampleColumnDataMap));
|
||||
String updateQueryTemplate = MessageFormat.format("UPDATE {0} SET {1} WHERE " +
|
||||
"1=0; -- Specify a valid condition here. Removing the condition may " +
|
||||
"1=0 -- Specify a valid condition here. Removing the condition may " +
|
||||
"update every row in the table!", table.getName(),
|
||||
getSampleOneColumnUpdateString(columnNameToSampleColumnDataMap));
|
||||
String deleteQueryTemplate = MessageFormat.format("DELETE FROM {0} WHERE 1=0;" +
|
||||
String deleteQueryTemplate = MessageFormat.format("DELETE FROM {0} WHERE 1=0" +
|
||||
" -- Specify a valid condition here. Removing the condition may " +
|
||||
"delete everything in the table!", table.getName());
|
||||
|
||||
|
|
@ -460,7 +460,7 @@ public class OracleDatasourceUtils {
|
|||
int activeConnections = poolProxy.getActiveConnections();
|
||||
int totalConnections = poolProxy.getTotalConnections();
|
||||
int threadsAwaitingConnection = poolProxy.getThreadsAwaitingConnection();
|
||||
log.debug("{0}: Hikari Pool stats : active - {1} , idle - {2}, awaiting - {3} , total - {4}", logPrefix,
|
||||
activeConnections, idleConnections, threadsAwaitingConnection, totalConnections);
|
||||
log.debug(MessageFormat.format("{0}: Hikari Pool stats : active - {1} , idle - {2}, awaiting - {3} , total - {4}",
|
||||
logPrefix, activeConnections, idleConnections, threadsAwaitingConnection, totalConnections));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.external.plugins.utils;
|
|||
|
||||
import com.appsmith.external.plugins.SmartSubstitutionInterface;
|
||||
import oracle.jdbc.OracleArray;
|
||||
import oracle.jdbc.OracleBlob;
|
||||
import oracle.sql.CLOB;
|
||||
import oracle.sql.Datum;
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
|
@ -13,9 +13,9 @@ import java.sql.ResultSetMetaData;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -32,6 +32,8 @@ public class OracleExecuteUtils implements SmartSubstitutionInterface {
|
|||
public static final String TIMESTAMPLTZ_TYPE_NAME = "TIMESTAMP WITH LOCAL TIME ZONE";
|
||||
public static final String CLOB_TYPE_NAME = "CLOB";
|
||||
public static final String NCLOB_TYPE_NAME = "NCLOB";
|
||||
public static final String RAW_TYPE_NAME = "RAW";
|
||||
public static final String BLOB_TYPE_NAME = "BLOB";
|
||||
public static final String AFFECTED_ROWS_KEY = "affectedRows";
|
||||
|
||||
/**
|
||||
|
|
@ -136,23 +138,36 @@ public class OracleExecuteUtils implements SmartSubstitutionInterface {
|
|||
} else if (DATE_COLUMN_TYPE_NAME.equalsIgnoreCase(typeName)) {
|
||||
value = DateTimeFormatter.ISO_DATE.format(resultSet.getDate(i).toLocalDate());
|
||||
|
||||
} else if (TIMESTAMP_TYPE_NAME.equalsIgnoreCase(typeName)) {
|
||||
value = DateTimeFormatter.ISO_DATE_TIME.format(
|
||||
LocalDateTime.of(
|
||||
resultSet.getDate(i).toLocalDate(),
|
||||
resultSet.getTime(i).toLocalTime()
|
||||
)
|
||||
) + "Z";
|
||||
|
||||
} else if (TIMESTAMPTZ_TYPE_NAME.equalsIgnoreCase(typeName) || TIMESTAMPLTZ_TYPE_NAME.equalsIgnoreCase(typeName)) {
|
||||
} else if (TIMESTAMP_TYPE_NAME.equalsIgnoreCase(typeName) || TIMESTAMPTZ_TYPE_NAME.equalsIgnoreCase(typeName) || TIMESTAMPLTZ_TYPE_NAME.equalsIgnoreCase(typeName)) {
|
||||
value = DateTimeFormatter.ISO_DATE_TIME.format(
|
||||
resultSet.getObject(i, OffsetDateTime.class)
|
||||
);
|
||||
|
||||
} else if (CLOB_TYPE_NAME.equalsIgnoreCase(typeName) || NCLOB_TYPE_NAME.equals(typeName)) {
|
||||
/**
|
||||
* clob, nclob are textual data.
|
||||
* Ref: https://docs.oracle.com/javadb/10.10.1.2/ref/rrefclob.html
|
||||
*/
|
||||
value = String.valueOf(((CLOB)resultSet.getObject(i)).getTarget().getPrefetchedData());
|
||||
} else if (resultSet.getObject(i) instanceof OracleArray) {
|
||||
value = ((OracleArray)resultSet.getObject(i)).getArray();
|
||||
} else if (RAW_TYPE_NAME.equalsIgnoreCase(typeName)) {
|
||||
/**
|
||||
* Raw / Blob data cannot be interpreted as anything but a byte array. Hence, send it back as a
|
||||
* base64 encoded string. The correct way to read the data for these types is for the user to
|
||||
* cast them to a type before reading them, example:
|
||||
* select utl_raw.cast_to_varchar2(c_raw) as c_raw, utl_raw.cast_to_varchar2(c_blob) as c_blob from TYPESTEST4
|
||||
*/
|
||||
value = Base64.getEncoder().encodeToString((byte[]) resultSet.getObject(i));
|
||||
}
|
||||
else if (BLOB_TYPE_NAME.equalsIgnoreCase(typeName)) {
|
||||
/**
|
||||
* Raw / Blob data cannot be interpreted as anything but a byte array. Hence, send it back as a
|
||||
* base64 encoded string. The correct way to read the data for these types is for the user to
|
||||
* cast them to a type before reading them, example:
|
||||
* select utl_raw.cast_to_varchar2(c_raw) as c_raw, utl_raw.cast_to_varchar2(c_blob) as c_blob from TYPESTEST4
|
||||
*/
|
||||
value = ((OracleBlob)resultSet.getObject(i)).getBytes(1L,
|
||||
(int) ((OracleBlob)resultSet.getObject(i)).length());
|
||||
}
|
||||
else {
|
||||
value = resultSet.getObject(i).toString();
|
||||
|
|
|
|||
328
app/server/appsmith-plugins/oraclePlugin/src/test/java/com/external/plugins/OracleExecutionTest.java
vendored
Normal file
328
app/server/appsmith-plugins/oraclePlugin/src/test/java/com/external/plugins/OracleExecutionTest.java
vendored
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
package com.external.plugins;
|
||||
|
||||
import com.appsmith.external.datatypes.ClientDataType;
|
||||
import com.appsmith.external.dtos.ExecuteActionDTO;
|
||||
import com.appsmith.external.models.ActionConfiguration;
|
||||
import com.appsmith.external.models.ActionExecutionResult;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.OracleContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.appsmith.external.helpers.PluginUtils.getExecuteDTOForTestWithBindingAndValueAndDataType;
|
||||
import static com.appsmith.external.helpers.PluginUtils.setDataValueSafelyInFormData;
|
||||
import static com.external.plugins.OracleTestDBContainerManager.getDefaultDatasourceConfig;
|
||||
import static com.external.plugins.OracleTestDBContainerManager.oraclePluginExecutor;
|
||||
import static com.external.plugins.OracleTestDBContainerManager.runSQLQueryOnOracleTestDB;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Testcontainers
|
||||
public class OracleExecutionTest {
|
||||
public static final String SQL_QUERY_CREATE_TABLE_FORMAT =
|
||||
"create table {0} (\n" +
|
||||
"c_varchar2 varchar2(20),\n" +
|
||||
"c_nvarchar2 nvarchar2(20),\n" +
|
||||
"c_number number,\n" +
|
||||
"c_float float,\n" +
|
||||
"c_date date,\n" +
|
||||
"c_binary_float binary_float,\n" +
|
||||
"c_binary_double binary_double,\n" +
|
||||
"c_timestamp timestamp,\n" +
|
||||
"c_timestamp_tz timestamp with time zone,\n" +
|
||||
"c_timestamp_ltz timestamp with local time zone,\n" +
|
||||
"c_interval_year interval year to month,\n" +
|
||||
"c_interval_day interval day to second,\n" +
|
||||
"c_rowid rowid,\n" +
|
||||
"c_urowid urowid,\n" +
|
||||
"c_char char(20),\n" +
|
||||
"c_nchar nchar(20),\n" +
|
||||
"c_clob clob,\n" +
|
||||
"c_nclob nclob\n" +
|
||||
")\n";
|
||||
private static final String SQL_QUERY_TO_INSERT_ONE_ROW_FORMAT =
|
||||
"insert into {0} values (\n" +
|
||||
"''varchar2'',\n" +
|
||||
"''nvarchar2'',\n" +
|
||||
"{1},\n" +
|
||||
"11.22,\n" +
|
||||
"''03-OCT-02'',\n" +
|
||||
"11.22,\n" +
|
||||
"11.22,\n" +
|
||||
"TIMESTAMP''1997-01-01 09:26:50.124'',\n" +
|
||||
"TIMESTAMP''1997-01-01 09:26:56.66 +02:00'',\n" +
|
||||
"TIMESTAMP''1999-04-05 8:00:00 US/Pacific'',\n" +
|
||||
"INTERVAL ''1'' YEAR(3),\n" +
|
||||
"INTERVAL ''1'' HOUR,\n" +
|
||||
"''000001F8.0001.0006'',\n" +
|
||||
"''000001F8.0001.0006'',\n" +
|
||||
"''char'',\n" +
|
||||
"''nchar'',\n" +
|
||||
"''clob'',\n" +
|
||||
"''nclob''\n" +
|
||||
")";
|
||||
|
||||
private static final String SQL_QUERY_TO_INSERT_ONE_ROW_WITH_BINDING_FORMAT =
|
||||
"insert into {0} values (\n" +
|
||||
"'{{'binding1'}}',\n" +
|
||||
"'{{'binding2'}}',\n" +
|
||||
"'{{'binding3'}}',\n" +
|
||||
"'{{'binding4'}}',\n" +
|
||||
"'{{'binding5'}}',\n" +
|
||||
"'{{'binding6'}}',\n" +
|
||||
"'{{'binding7'}}',\n" +
|
||||
"TO_TIMESTAMP('{{'binding8'}}', ''YYYY-MM-DD HH24:MI:SS.FF''),\n" +
|
||||
"TO_TIMESTAMP('{{'binding9'}}', ''YYYY-MM-DD HH24:MI:SS.FF''),\n" +
|
||||
"TO_TIMESTAMP('{{'binding10'}}', ''YYYY-MM-DD HH24:MI:SS.FF''),\n" +
|
||||
"NUMTOYMINTERVAL('{{'binding11'}}', ''YEAR''),\n" +
|
||||
"NUMTODSINTERVAL('{{'binding12'}}', ''HOUR''),\n" +
|
||||
"'{{'binding13'}}',\n" +
|
||||
"'{{'binding14'}}',\n" +
|
||||
"'{{'binding15'}}',\n" +
|
||||
"'{{'binding16'}}',\n" +
|
||||
"'{{'binding17'}}',\n" +
|
||||
"'{{'binding18'}}'\n" +
|
||||
")";
|
||||
|
||||
public static final String SELECT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME = "testSelectWithPreparedStatementWithoutAnyBinding";
|
||||
public static final String SELECT_TEST_WITH_PREPARED_STMT_TABLE_NAME = "testSelectWithPreparedStatementWithBinding";
|
||||
public static final String INSERT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME = "testInsertWithPreparedStatementWithoutAnyBinding";
|
||||
public static final String INSERT_TEST_WITH_PREPARED_STMT_TABLE_NAME = "testInsertWithPreparedStatementWithBinding";
|
||||
public static final String UPDATE_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME = "testUpdateWithPreparedStatementWithoutAnyBinding";
|
||||
public static final String UPDATE_TEST_WITH_PREPARED_STMT_TABLE_NAME = "testUpdateWithPreparedStatementWithBinding";
|
||||
public static final String DELETE_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME = "testDeleteWithPreparedStatementWithoutAnyBinding";
|
||||
public static final String DELETE_TEST_WITH_PREPARED_STMT_TABLE_NAME = "testDeleteWithPreparedStatementWithBinding";
|
||||
|
||||
@SuppressWarnings("rawtypes") // The type parameter for the container type is just itself and is pseudo-optional.
|
||||
@Container
|
||||
private static final OracleContainer oracleDB = OracleTestDBContainerManager.getOracleDBForTest();
|
||||
|
||||
private static HikariDataSource sharedConnectionPool = null;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws SQLException {
|
||||
sharedConnectionPool = oraclePluginExecutor.datasourceCreate(getDefaultDatasourceConfig(oracleDB)).block();
|
||||
createTablesForTest();
|
||||
}
|
||||
|
||||
public static void createTablesForTest() throws SQLException {
|
||||
createTableWithName(SELECT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME);
|
||||
createTableWithName(SELECT_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
createTableWithName(INSERT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME);
|
||||
createTableWithName(INSERT_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
createTableWithName(UPDATE_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME);
|
||||
createTableWithName(UPDATE_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
createTableWithName(DELETE_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME);
|
||||
createTableWithName(DELETE_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
}
|
||||
|
||||
private static void createTableWithName(String tableName) throws SQLException {
|
||||
String sqlQueryToCreateTable = MessageFormat.format(SQL_QUERY_CREATE_TABLE_FORMAT, tableName);
|
||||
runSQLQueryOnOracleTestDB(sqlQueryToCreateTable, sharedConnectionPool);
|
||||
|
||||
String sqlQueryToInsertRow1 = MessageFormat.format(SQL_QUERY_TO_INSERT_ONE_ROW_FORMAT, tableName, 1);
|
||||
runSQLQueryOnOracleTestDB(sqlQueryToInsertRow1, sharedConnectionPool);
|
||||
|
||||
String sqlQueryToInsertRow2 = MessageFormat.format(SQL_QUERY_TO_INSERT_ONE_ROW_FORMAT, tableName, 2);
|
||||
runSQLQueryOnOracleTestDB(sqlQueryToInsertRow2, sharedConnectionPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectQueryWithPreparedStatementWithoutAnyBinding() {
|
||||
String sqlSelectQuery = MessageFormat.format("SELECT c_number FROM {0} ORDER BY c_number",
|
||||
SELECT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME);
|
||||
Map formData = setDataValueSafelyInFormData(null, "body", sqlSelectQuery);
|
||||
ActionConfiguration actionConfig = new ActionConfiguration();
|
||||
actionConfig.setFormData(formData);
|
||||
Mono<ActionExecutionResult> executionResultMono = oraclePluginExecutor.executeParameterized(sharedConnectionPool, new ExecuteActionDTO(),
|
||||
getDefaultDatasourceConfig(oracleDB), actionConfig);
|
||||
String expectedResultString = "[{\"C_NUMBER\":\"1\"},{\"C_NUMBER\":\"2\"}]";
|
||||
verifyColumnValue(executionResultMono, expectedResultString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryWorksWithSemicolonInTheEnd() {
|
||||
String sqlSelectQuery = MessageFormat.format("SELECT c_number FROM {0} ORDER BY c_number;",
|
||||
SELECT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME);
|
||||
Map formData = setDataValueSafelyInFormData(null, "body", sqlSelectQuery);
|
||||
ActionConfiguration actionConfig = new ActionConfiguration();
|
||||
actionConfig.setFormData(formData);
|
||||
Mono<ActionExecutionResult> executionResultMono = oraclePluginExecutor.executeParameterized(sharedConnectionPool, new ExecuteActionDTO(),
|
||||
getDefaultDatasourceConfig(oracleDB), actionConfig);
|
||||
String expectedResultString = "[{\"C_NUMBER\":\"1\"},{\"C_NUMBER\":\"2\"}]";
|
||||
verifyColumnValue(executionResultMono, expectedResultString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectQueryWithPreparedStatementWithBinding() {
|
||||
String sqlSelectQuery = MessageFormat.format("SELECT c_number FROM {0} WHERE " +
|
||||
"c_varchar2='{{'binding1'}}' ORDER BY c_number DESC", SELECT_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
Map formData = setDataValueSafelyInFormData(null, "body", sqlSelectQuery);
|
||||
ActionConfiguration actionConfig = new ActionConfiguration();
|
||||
actionConfig.setFormData(formData);
|
||||
|
||||
LinkedHashMap<String, List> bindingNameToValueAndDataTypeMap = new LinkedHashMap<>();
|
||||
bindingNameToValueAndDataTypeMap.put("binding1", List.of("varchar2", ClientDataType.STRING));
|
||||
ExecuteActionDTO executeActionDTO =
|
||||
getExecuteDTOForTestWithBindingAndValueAndDataType(bindingNameToValueAndDataTypeMap);
|
||||
|
||||
Mono<ActionExecutionResult> executionResultMono =
|
||||
oraclePluginExecutor.executeParameterized(sharedConnectionPool, executeActionDTO,
|
||||
getDefaultDatasourceConfig(oracleDB), actionConfig);
|
||||
String expectedResultString = "[{\"C_NUMBER\":\"2\"},{\"C_NUMBER\":\"1\"}]";
|
||||
verifyColumnValue(executionResultMono, expectedResultString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertQueryReturnValueWithPreparedStatementWithoutAnyBinding() {
|
||||
String sqlInsertQuery = MessageFormat.format(SQL_QUERY_TO_INSERT_ONE_ROW_FORMAT,
|
||||
INSERT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME, 3);
|
||||
Map insertQueryFormData = setDataValueSafelyInFormData(null, "body", sqlInsertQuery);
|
||||
ActionConfiguration insertQueryActionConfig = new ActionConfiguration();
|
||||
insertQueryActionConfig.setFormData(insertQueryFormData);
|
||||
Mono<ActionExecutionResult> insertQueryExecutionResultMono =
|
||||
oraclePluginExecutor.executeParameterized(sharedConnectionPool, new ExecuteActionDTO(),
|
||||
getDefaultDatasourceConfig(oracleDB), insertQueryActionConfig);
|
||||
String insertQueryExpectedResultString = "[{\"affectedRows\":1}]";
|
||||
verifyColumnValue(insertQueryExecutionResultMono, insertQueryExpectedResultString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertQueryVerifyNewRowAddedWithPreparedStatementWithoutAnyBinding() {
|
||||
String sqlInsertQuery = MessageFormat.format(SQL_QUERY_TO_INSERT_ONE_ROW_FORMAT,
|
||||
INSERT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME, 4);
|
||||
Map insertQueryFormData = setDataValueSafelyInFormData(null, "body", sqlInsertQuery);
|
||||
ActionConfiguration insertQueryActionConfig = new ActionConfiguration();
|
||||
insertQueryActionConfig.setFormData(insertQueryFormData);
|
||||
oraclePluginExecutor.executeParameterized(sharedConnectionPool, new ExecuteActionDTO(),
|
||||
getDefaultDatasourceConfig(oracleDB), insertQueryActionConfig).block();
|
||||
|
||||
String sqlSelectQuery = MessageFormat.format("SELECT * FROM {0} WHERE c_number=4",
|
||||
INSERT_TEST_WITHOUT_PREPARED_STMT_TABLE_NAME);
|
||||
Map selectQueryFormData = setDataValueSafelyInFormData(null, "body", sqlSelectQuery);
|
||||
ActionConfiguration selectQueryActionConfig = new ActionConfiguration();
|
||||
selectQueryActionConfig.setFormData(selectQueryFormData);
|
||||
Mono<ActionExecutionResult> selectQueryExecutionResultMono =
|
||||
oraclePluginExecutor.executeParameterized(sharedConnectionPool, new ExecuteActionDTO(),
|
||||
getDefaultDatasourceConfig(oracleDB), selectQueryActionConfig);
|
||||
String selectQueryExpectedResultString = "[{\"C_VARCHAR2\":\"varchar2\",\"C_NVARCHAR2\":\"nvarchar2\"," +
|
||||
"\"C_NUMBER\":\"4\",\"C_FLOAT\":\"11.22\",\"C_DATE\":\"2002-10-03\",\"C_BINARY_FLOAT\":\"11.22\"," +
|
||||
"\"C_BINARY_DOUBLE\":\"11.22\",\"C_TIMESTAMP\":\"1997-01-01T09:26:50.124Z\"," +
|
||||
"\"C_TIMESTAMP_TZ\":\"1997-01-01T09:26:56.66+02:00\",\"C_TIMESTAMP_LTZ\":\"1999-04-05T15:00:00Z\"," +
|
||||
"\"C_INTERVAL_YEAR\":\"1-0\",\"C_INTERVAL_DAY\":\"0 1:0:0.0\",\"C_ROWID\":\"AAAAAAAAGAAAAH4AAB\"," +
|
||||
"\"C_UROWID\":\"000001F8.0001.0006\",\"C_CHAR\":\"char \",\"C_NCHAR\":\"nchar " +
|
||||
" \",\"C_CLOB\":\"clob\",\"C_NCLOB\":\"nclob\"}]";
|
||||
verifyColumnValue(selectQueryExecutionResultMono, selectQueryExpectedResultString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertQueryReturnValueWithPreparedStatementWithBinding() {
|
||||
String sqlInsertQuery = MessageFormat.format(SQL_QUERY_TO_INSERT_ONE_ROW_WITH_BINDING_FORMAT,
|
||||
INSERT_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
Map insertQueryFormData = setDataValueSafelyInFormData(null, "body", sqlInsertQuery);
|
||||
ActionConfiguration insertQueryActionConfig = new ActionConfiguration();
|
||||
insertQueryActionConfig.setFormData(insertQueryFormData);
|
||||
|
||||
LinkedHashMap<String, List> bindingNameToValueAndDataTypeMap = new LinkedHashMap<>();
|
||||
bindingNameToValueAndDataTypeMap.put("binding1", List.of("varchar2", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding2", List.of("nvarchar2", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding3", List.of("3", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding4", List.of("11.22", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding5", List.of("03-OCT-02", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding6", List.of("11.22", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding7", List.of("11.22", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding8", List.of("1997-01-01 09:26:50.124", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding9", List.of("1997-01-01 09:26:50.124", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding10", List.of("1997-01-01 09:26:50.124", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding11", List.of("1", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding12", List.of("1", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding13", List.of("000001F8.0001.0006", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding14", List.of("000001F8.0001.0006", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding15", List.of("char", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding16", List.of("nchar", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding17", List.of("clob", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding18", List.of("nclob", ClientDataType.STRING));
|
||||
|
||||
ExecuteActionDTO executeActionDTO =
|
||||
getExecuteDTOForTestWithBindingAndValueAndDataType(bindingNameToValueAndDataTypeMap);
|
||||
|
||||
Mono<ActionExecutionResult> insertQueryExecutionResultMono =
|
||||
oraclePluginExecutor.executeParameterized(sharedConnectionPool, executeActionDTO,
|
||||
getDefaultDatasourceConfig(oracleDB), insertQueryActionConfig);
|
||||
String insertQueryExpectedResultString = "[{\"affectedRows\":1}]";
|
||||
verifyColumnValue(insertQueryExecutionResultMono, insertQueryExpectedResultString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertQueryVerifyNewRowAddedWithPreparedStatementWithBinding() {
|
||||
String sqlInsertQuery = MessageFormat.format(SQL_QUERY_TO_INSERT_ONE_ROW_WITH_BINDING_FORMAT,
|
||||
INSERT_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
Map insertQueryFormData = setDataValueSafelyInFormData(null, "body", sqlInsertQuery);
|
||||
ActionConfiguration insertQueryActionConfig = new ActionConfiguration();
|
||||
insertQueryActionConfig.setFormData(insertQueryFormData);
|
||||
|
||||
LinkedHashMap<String, List> bindingNameToValueAndDataTypeMap = new LinkedHashMap<>();
|
||||
bindingNameToValueAndDataTypeMap.put("binding1", List.of("varchar2", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding2", List.of("nvarchar2", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding3", List.of("5", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding4", List.of("11.22", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding5", List.of("03-OCT-02", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding6", List.of("11.22", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding7", List.of("11.22", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding8", List.of("1997-01-01 09:26:50.124", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding9", List.of("1997-01-01 09:26:50.124", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding10", List.of("1997-01-01 09:26:50.124", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding11", List.of("1", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding12", List.of("1", ClientDataType.NUMBER));
|
||||
bindingNameToValueAndDataTypeMap.put("binding13", List.of("000001F8.0001.0006", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding14", List.of("000001F8.0001.0006", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding15", List.of("char", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding16", List.of("nchar", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding17", List.of("clob", ClientDataType.STRING));
|
||||
bindingNameToValueAndDataTypeMap.put("binding18", List.of("nclob", ClientDataType.STRING));
|
||||
|
||||
ExecuteActionDTO executeActionDTO =
|
||||
getExecuteDTOForTestWithBindingAndValueAndDataType(bindingNameToValueAndDataTypeMap);
|
||||
oraclePluginExecutor.executeParameterized(sharedConnectionPool, executeActionDTO,
|
||||
getDefaultDatasourceConfig(oracleDB), insertQueryActionConfig).block();
|
||||
|
||||
String sqlSelectQuery = MessageFormat.format("SELECT c_varchar2, c_nvarchar2, c_number, c_float, c_date, " +
|
||||
"c_binary_float, c_binary_double, c_timestamp, c_interval_year, " +
|
||||
"c_interval_day, c_rowid, c_urowid, c_char, c_nchar, c_clob, c_nclob FROM {0} WHERE c_number=5",
|
||||
INSERT_TEST_WITH_PREPARED_STMT_TABLE_NAME);
|
||||
Map selectQueryFormData = setDataValueSafelyInFormData(null, "body", sqlSelectQuery);
|
||||
ActionConfiguration selectQueryActionConfig = new ActionConfiguration();
|
||||
selectQueryActionConfig.setFormData(selectQueryFormData);
|
||||
Mono<ActionExecutionResult> selectQueryExecutionResultMono =
|
||||
oraclePluginExecutor.executeParameterized(sharedConnectionPool, new ExecuteActionDTO(),
|
||||
getDefaultDatasourceConfig(oracleDB), selectQueryActionConfig);
|
||||
String selectQueryExpectedResultString = "[{\"C_VARCHAR2\":\"varchar2\",\"C_NVARCHAR2\":\"nvarchar2\"," +
|
||||
"\"C_NUMBER\":\"5\",\"C_FLOAT\":\"11.22\",\"C_DATE\":\"2002-10-03\",\"C_BINARY_FLOAT\":\"11.22\"," +
|
||||
"\"C_BINARY_DOUBLE\":\"11.22\",\"C_TIMESTAMP\":\"1997-01-01T09:26:50.124Z\"," +
|
||||
"\"C_INTERVAL_YEAR\":\"1-0\",\"C_INTERVAL_DAY\":\"0 1:0:0.0\"," +
|
||||
"\"C_ROWID\":\"AAAAAAAAGAAAAH4AAB\",\"C_UROWID\":\"000001F8.0001.0006\",\"C_CHAR\":\"char " +
|
||||
" \",\"C_NCHAR\":\"nchar \",\"C_CLOB\":\"clob\",\"C_NCLOB\":\"nclob\"}]";
|
||||
verifyColumnValue(selectQueryExecutionResultMono, selectQueryExpectedResultString);
|
||||
}
|
||||
|
||||
private void verifyColumnValue(Mono<ActionExecutionResult> executionResultMono, String expectedResult) {
|
||||
StepVerifier.create(executionResultMono)
|
||||
.assertNext(actionExecutionResult -> {
|
||||
assertTrue(actionExecutionResult.getIsExecutionSuccess(), actionExecutionResult.getBody().toString());
|
||||
if (expectedResult != null) {
|
||||
assertEquals(expectedResult, actionExecutionResult.getBody().toString());
|
||||
}
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
package com.external.plugins;
|
||||
|
||||
import com.appsmith.external.models.DatasourceStructure;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.OracleContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.appsmith.external.helpers.PluginUtils.STRING_TYPE;
|
||||
import static com.appsmith.external.helpers.PluginUtils.getDataValueSafelyFromFormData;
|
||||
import static com.external.plugins.OracleTestDBContainerManager.getDefaultDatasourceConfig;
|
||||
import static com.external.plugins.OracleTestDBContainerManager.oraclePluginExecutor;
|
||||
import static com.external.plugins.OracleTestDBContainerManager.runSQLQueryOnOracleTestDB;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Testcontainers
|
||||
public class OracleGetDBSchemaTest {
|
||||
public static final String SQL_QUERY_TO_CREATE_TABLE_WITH_PRIMARY_KEY =
|
||||
"CREATE TABLE supplier\n" +
|
||||
"( supplier_id numeric(10) not null,\n" +
|
||||
" supplier_name varchar2(50) not null,\n" +
|
||||
" contact_name varchar2(50),\n" +
|
||||
" CONSTRAINT supplier_pk PRIMARY KEY (supplier_id)\n" +
|
||||
")";
|
||||
|
||||
public static final String SQL_QUERY_TO_CREATE_TABLE_WITH_FOREIGN_KEY =
|
||||
"CREATE TABLE products\n" +
|
||||
"( product_id numeric(10) not null,\n" +
|
||||
" supplier_id numeric(10) not null,\n" +
|
||||
" CONSTRAINT fk_supplier\n" +
|
||||
" FOREIGN KEY (supplier_id)\n" +
|
||||
" REFERENCES supplier(supplier_id)\n" +
|
||||
")";
|
||||
|
||||
@SuppressWarnings("rawtypes") // The type parameter for the container type is just itself and is pseudo-optional.
|
||||
@Container
|
||||
private static final OracleContainer oracleDB = OracleTestDBContainerManager.getOracleDBForTest();
|
||||
|
||||
private static HikariDataSource sharedConnectionPool = null;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws SQLException {
|
||||
sharedConnectionPool = oraclePluginExecutor.datasourceCreate(getDefaultDatasourceConfig(oracleDB)).block();
|
||||
createTablesForTest();
|
||||
}
|
||||
|
||||
private static void createTablesForTest() throws SQLException {
|
||||
runSQLQueryOnOracleTestDB(SQL_QUERY_TO_CREATE_TABLE_WITH_PRIMARY_KEY, sharedConnectionPool);
|
||||
runSQLQueryOnOracleTestDB(SQL_QUERY_TO_CREATE_TABLE_WITH_FOREIGN_KEY, sharedConnectionPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDBSchemaShowsAllTables() {
|
||||
Mono<DatasourceStructure> datasourceStructureMono =
|
||||
oraclePluginExecutor.getStructure(sharedConnectionPool,
|
||||
getDefaultDatasourceConfig(oracleDB));
|
||||
|
||||
StepVerifier.create(datasourceStructureMono)
|
||||
.assertNext(datasourceStructure -> {
|
||||
Set<String> setOfAllTableNames = datasourceStructure.getTables().stream()
|
||||
.map(DatasourceStructure.Table::getName)
|
||||
.map(String::toLowerCase)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
assertTrue(setOfAllTableNames.equals(Set.of("supplier","products")), setOfAllTableNames.toString());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDBSchemaShowsAllColumnsAndTypesInATable() {
|
||||
Mono<DatasourceStructure> datasourceStructureMono =
|
||||
oraclePluginExecutor.getStructure(sharedConnectionPool,
|
||||
getDefaultDatasourceConfig(oracleDB));
|
||||
|
||||
StepVerifier.create(datasourceStructureMono)
|
||||
.assertNext(datasourceStructure -> {
|
||||
DatasourceStructure.Table supplierTable = datasourceStructure.getTables().stream()
|
||||
.filter(table -> "supplier".equalsIgnoreCase(table.getName()))
|
||||
.findFirst()
|
||||
.get();
|
||||
|
||||
assertTrue(supplierTable != null, "supplier table not found in DB schema");
|
||||
|
||||
Set<String> allColumnNames = supplierTable.getColumns().stream()
|
||||
.map(DatasourceStructure.Column::getName)
|
||||
.map(String::toLowerCase)
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> expectedColumnNames = Set.of("supplier_id", "supplier_name", "contact_name");
|
||||
assertEquals(expectedColumnNames, allColumnNames, allColumnNames.toString());
|
||||
|
||||
supplierTable.getColumns().stream()
|
||||
.forEach(column -> {
|
||||
String columnName = column.getName().toLowerCase();
|
||||
String columnType = column.getType().toLowerCase();
|
||||
String expectedColumnType = null;
|
||||
|
||||
if ("supplier_id".equals(columnName)) {
|
||||
expectedColumnType = "number";
|
||||
}
|
||||
else {
|
||||
expectedColumnType = "varchar2";
|
||||
}
|
||||
|
||||
assertEquals(expectedColumnType, columnType, columnType);
|
||||
});
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDynamicSqlTemplateQueriesForATable() {
|
||||
Mono<DatasourceStructure> datasourceStructureMono =
|
||||
oraclePluginExecutor.getStructure(sharedConnectionPool,
|
||||
getDefaultDatasourceConfig(oracleDB));
|
||||
|
||||
StepVerifier.create(datasourceStructureMono)
|
||||
.assertNext(datasourceStructure -> {
|
||||
DatasourceStructure.Table supplierTable = datasourceStructure.getTables().stream()
|
||||
.filter(table -> "supplier".equalsIgnoreCase(table.getName()))
|
||||
.findFirst()
|
||||
.get();
|
||||
|
||||
assertTrue(supplierTable != null, "supplier table not found in DB schema");
|
||||
|
||||
supplierTable.getTemplates().stream()
|
||||
.filter(template -> "select".equalsIgnoreCase(template.getTitle()) || "delete".equalsIgnoreCase(template.getTitle()))
|
||||
.forEach(template -> {
|
||||
/**
|
||||
* Not sure how to test query templates for insert and update queries as these
|
||||
* queries include column names in an order that is not fixed. Hence, skipping testing
|
||||
* them for now.
|
||||
*/
|
||||
|
||||
String expectedSelectQueryTemplate = null;
|
||||
if ("select".equalsIgnoreCase(template.getTitle())) {
|
||||
expectedSelectQueryTemplate = "select * from supplier where rownum < 10";
|
||||
}
|
||||
else if ("delete".equalsIgnoreCase(template.getTitle())) {
|
||||
expectedSelectQueryTemplate = "delete from supplier where 1=0 -- specify a valid" +
|
||||
" condition here. removing the condition may delete everything in the " +
|
||||
"table!";
|
||||
}
|
||||
|
||||
String templateQuery =
|
||||
getDataValueSafelyFromFormData((Map<String, Object>) template.getConfiguration(), "body", STRING_TYPE);
|
||||
assertEquals(expectedSelectQueryTemplate, templateQuery.toLowerCase(),
|
||||
templateQuery.toLowerCase());
|
||||
});
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
}
|
||||
81
app/server/appsmith-plugins/oraclePlugin/src/test/java/com/external/plugins/OraclePluginConnectionTest.java
vendored
Executable file
81
app/server/appsmith-plugins/oraclePlugin/src/test/java/com/external/plugins/OraclePluginConnectionTest.java
vendored
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
package com.external.plugins;
|
||||
|
||||
|
||||
import com.appsmith.external.models.DBAuth;
|
||||
import com.appsmith.external.models.DatasourceConfiguration;
|
||||
import com.appsmith.external.models.DatasourceTestResult;
|
||||
import com.external.plugins.exceptions.OraclePluginError;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.OracleContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.external.plugins.OracleTestDBContainerManager.getDefaultDatasourceConfig;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Testcontainers
|
||||
public class OraclePluginConnectionTest {
|
||||
|
||||
OraclePlugin.OraclePluginExecutor oraclePluginExecutor = new OraclePlugin.OraclePluginExecutor();
|
||||
|
||||
@SuppressWarnings("rawtypes") // The type parameter for the container type is just itself and is pseudo-optional.
|
||||
@Container
|
||||
private static final OracleContainer oracleDB = OracleTestDBContainerManager.getOracleDBForTest();
|
||||
|
||||
@Test
|
||||
public void testDatasourceConnectionTestPassWithValidConfig() {
|
||||
Mono<DatasourceTestResult> testDsResultMono =
|
||||
oraclePluginExecutor.testDatasource(getDefaultDatasourceConfig(oracleDB));
|
||||
StepVerifier.create(testDsResultMono)
|
||||
.assertNext(testResult -> {
|
||||
assertEquals(0, testResult.getInvalids().size());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDatasourceConnectionTestFailWithInvalidPassword() {
|
||||
DatasourceConfiguration invalidDsConfig = getDefaultDatasourceConfig(oracleDB);
|
||||
((DBAuth)invalidDsConfig.getAuthentication()).setPassword("invalid_password");
|
||||
|
||||
Mono<DatasourceTestResult> testDsResultMono =
|
||||
oraclePluginExecutor.testDatasource(invalidDsConfig);
|
||||
StepVerifier.create(testDsResultMono)
|
||||
.assertNext(testResult -> {
|
||||
assertNotEquals(0, testResult.getInvalids().size());
|
||||
String expectedError = "Failed to initialize pool: ORA-01017: invalid username/password; logon " +
|
||||
"denied";
|
||||
boolean isExpectedErrorReceived = testResult.getInvalids().stream()
|
||||
.anyMatch(errorString -> expectedError.equals(errorString.trim()));
|
||||
assertTrue(isExpectedErrorReceived);
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDatasourceConnectionTestFailWithInvalidUsername() {
|
||||
DatasourceConfiguration invalidDsConfig = getDefaultDatasourceConfig(oracleDB);
|
||||
((DBAuth)invalidDsConfig.getAuthentication()).setUsername("invalid_username");
|
||||
|
||||
Mono<DatasourceTestResult> testDsResultMono =
|
||||
oraclePluginExecutor.testDatasource(invalidDsConfig);
|
||||
StepVerifier.create(testDsResultMono)
|
||||
.assertNext(testResult -> {
|
||||
assertNotEquals(0, testResult.getInvalids().size());
|
||||
String expectedError = "Failed to initialize pool: ORA-01017: invalid username/password; logon " +
|
||||
"denied";
|
||||
boolean isExpectedErrorReceived = testResult.getInvalids().stream()
|
||||
.anyMatch(errorString -> expectedError.equals(errorString.trim()));
|
||||
assertTrue(isExpectedErrorReceived);
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.external.plugins;
|
||||
|
||||
import com.appsmith.external.models.DBAuth;
|
||||
import com.appsmith.external.models.DatasourceConfiguration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.external.plugins.OracleTestDBContainerManager.getDefaultDatasourceConfig;
|
||||
import static com.external.plugins.exceptions.OracleErrorMessages.DS_MISSING_ENDPOINT_ERROR_MSG;
|
||||
import static com.external.plugins.exceptions.OracleErrorMessages.DS_MISSING_HOSTNAME_ERROR_MSG;
|
||||
import static com.external.plugins.exceptions.OracleErrorMessages.DS_MISSING_PASSWORD_ERROR_MSG;
|
||||
import static com.external.plugins.exceptions.OracleErrorMessages.DS_MISSING_USERNAME_ERROR_MSG;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class OraclePluginDatasourceValidityErrorsTest {
|
||||
|
||||
OraclePlugin.OraclePluginExecutor oraclePluginExecutor = new OraclePlugin.OraclePluginExecutor();
|
||||
|
||||
@Test
|
||||
public void testErrorOnMissingUsername() {
|
||||
DatasourceConfiguration dsConfigWithMissingUsername = getDefaultDatasourceConfig(null);
|
||||
((DBAuth)dsConfigWithMissingUsername.getAuthentication()).setUsername("");
|
||||
|
||||
Set<String> dsValidateResult = oraclePluginExecutor.validateDatasource(dsConfigWithMissingUsername);
|
||||
boolean isExpectedErrorReceived = dsValidateResult.stream()
|
||||
.anyMatch(errorString -> DS_MISSING_USERNAME_ERROR_MSG.equals(errorString.trim()));
|
||||
assertTrue(isExpectedErrorReceived);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorOnMissingPassword() {
|
||||
DatasourceConfiguration dsConfigWithMissingPassword = getDefaultDatasourceConfig(null);
|
||||
((DBAuth)dsConfigWithMissingPassword.getAuthentication()).setPassword("");
|
||||
|
||||
Set<String> dsValidateResult = oraclePluginExecutor.validateDatasource(dsConfigWithMissingPassword);
|
||||
boolean isExpectedErrorReceived = dsValidateResult.stream()
|
||||
.anyMatch(errorString -> DS_MISSING_PASSWORD_ERROR_MSG.equals(errorString.trim()));
|
||||
assertTrue(isExpectedErrorReceived);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorOnMissingEndpoint() {
|
||||
DatasourceConfiguration dsConfigWithMissingEndpoint = getDefaultDatasourceConfig(null);
|
||||
dsConfigWithMissingEndpoint.setEndpoints(new ArrayList<>());
|
||||
|
||||
Set<String> dsValidateResult = oraclePluginExecutor.validateDatasource(dsConfigWithMissingEndpoint);
|
||||
boolean isExpectedErrorReceived = dsValidateResult.stream()
|
||||
.anyMatch(errorString -> DS_MISSING_ENDPOINT_ERROR_MSG.equals(errorString.trim()));
|
||||
assertTrue(isExpectedErrorReceived);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorOnMissingHost() {
|
||||
DatasourceConfiguration dsConfigWithMissingHost = getDefaultDatasourceConfig(null);
|
||||
dsConfigWithMissingHost.getEndpoints().get(0).setHost("");
|
||||
|
||||
Set<String> dsValidateResult = oraclePluginExecutor.validateDatasource(dsConfigWithMissingHost);
|
||||
boolean isExpectedErrorReceived = dsValidateResult.stream()
|
||||
.anyMatch(errorString -> DS_MISSING_HOSTNAME_ERROR_MSG.equals(errorString.trim()));
|
||||
assertTrue(isExpectedErrorReceived);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,12 @@
|
|||
package com.external.plugins;
|
||||
|
||||
|
||||
import com.external.plugins.exceptions.OraclePluginError;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Testcontainers
|
||||
public class OraclePluginTest {
|
||||
public class OraclePluginErrorsTest {
|
||||
@Test
|
||||
public void verifyUniquenessOfOraclePluginErrorCode() {
|
||||
assert (Arrays.stream(OraclePluginError.values()).map(OraclePluginError::getAppErrorCode).distinct().count() == OraclePluginError.values().length);
|
||||
|
|
@ -19,6 +14,5 @@ public class OraclePluginTest {
|
|||
assert (Arrays.stream(OraclePluginError.values()).map(OraclePluginError::getAppErrorCode)
|
||||
.filter(appErrorCode -> appErrorCode.length() != 11 || !appErrorCode.startsWith("PE-ORC"))
|
||||
.collect(Collectors.toList()).size() == 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.external.plugins;
|
||||
|
||||
import com.appsmith.external.models.Connection;
|
||||
import com.appsmith.external.models.DBAuth;
|
||||
import com.appsmith.external.models.DatasourceConfiguration;
|
||||
import com.appsmith.external.models.Endpoint;
|
||||
import com.appsmith.external.models.SSLDetails;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.testcontainers.containers.OracleContainer;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.external.plugins.utils.OracleDatasourceUtils.getConnectionFromConnectionPool;
|
||||
import static com.external.plugins.utils.OracleExecuteUtils.closeConnectionPostExecution;
|
||||
|
||||
public class OracleTestDBContainerManager {
|
||||
public static final String ORACLE_USERNAME = "testUser";
|
||||
public static final String ORACLE_PASSWORD = "testPassword";
|
||||
public static final String ORACLE_DB_NAME = "testDB";
|
||||
public static final String ORACLE_DOCKER_HUB_CONTAINER = "gvenzl/oracle-xe:21-slim-faststart";
|
||||
static OraclePlugin.OraclePluginExecutor oraclePluginExecutor = new OraclePlugin.OraclePluginExecutor();
|
||||
|
||||
public static OracleContainer getOracleDBForTest() {
|
||||
return new OracleContainer(ORACLE_DOCKER_HUB_CONTAINER)
|
||||
.withDatabaseName(ORACLE_DB_NAME)
|
||||
.withUsername(ORACLE_USERNAME)
|
||||
.withPassword(ORACLE_PASSWORD);
|
||||
}
|
||||
|
||||
public static DatasourceConfiguration getDefaultDatasourceConfig(OracleContainer oracleDB) {
|
||||
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
|
||||
dsConfig.setAuthentication(new DBAuth());
|
||||
((DBAuth)dsConfig.getAuthentication()).setUsername(OracleTestDBContainerManager.ORACLE_USERNAME);
|
||||
((DBAuth)dsConfig.getAuthentication()).setPassword(OracleTestDBContainerManager.ORACLE_PASSWORD);
|
||||
((DBAuth)dsConfig.getAuthentication()).setDatabaseName(OracleTestDBContainerManager.ORACLE_DB_NAME);
|
||||
|
||||
dsConfig.setEndpoints(new ArrayList<>());
|
||||
String host = oracleDB == null ? "host" : oracleDB.getHost();
|
||||
long port = oracleDB == null ? 1521L : (long)oracleDB.getOraclePort();
|
||||
dsConfig.getEndpoints().add(new Endpoint(host, port));
|
||||
|
||||
dsConfig.setConnection(new Connection());
|
||||
dsConfig.getConnection().setSsl(new SSLDetails());
|
||||
dsConfig.getConnection().getSsl().setAuthType(SSLDetails.AuthType.DISABLE);
|
||||
|
||||
return dsConfig;
|
||||
}
|
||||
|
||||
static void runSQLQueryOnOracleTestDB(String sqlQuery, HikariDataSource sharedConnectionPool) throws SQLException {
|
||||
java.sql.Connection connectionFromPool = getConnectionFromConnectionPool(sharedConnectionPool);
|
||||
Statement statement = connectionFromPool.createStatement();
|
||||
statement.execute(sqlQuery);
|
||||
closeConnectionPostExecution(null, statement, null, connectionFromPool);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user