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:
Sumit Kumar 2023-05-01 21:32:02 +05:30 committed by GitHub
parent aa7ef11aa1
commit 09fd519e2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 777 additions and 47 deletions

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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) {

View File

@ -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.";
/*
************************************************************************************************************************************************

View File

@ -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));
}
}

View File

@ -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();

View 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();
}
}

View File

@ -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();
}
}

View 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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}