Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.hop.core.CheckResult;
import org.apache.hop.core.ICheckResult;
import org.apache.hop.core.Result;
import org.apache.hop.core.RowMetaAndData;
import org.apache.hop.core.annotations.Action;
Expand All @@ -28,6 +31,7 @@
import org.apache.hop.i18n.BaseMessages;
import org.apache.hop.metadata.api.HopMetadataProperty;
import org.apache.hop.metadata.api.HopMetadataPropertyType;
import org.apache.hop.metadata.api.IHopMetadataProvider;
import org.apache.hop.resource.ResourceEntry;
import org.apache.hop.resource.ResourceEntry.ResourceType;
import org.apache.hop.resource.ResourceReference;
Expand Down Expand Up @@ -216,13 +220,13 @@ this, this, getParentWorkflowMeta().findDatabase(connection, getVariables()))) {
}
}
} catch (Exception dbe) {
result.setNrErrors(1);
updateErrors();
logError(
BaseMessages.getString(
PKG, "ActionTruncateTables.Error.RunningEntry", dbe.getMessage()));
}
} else {
result.setNrErrors(1);
updateErrors();
logError(BaseMessages.getString(PKG, "ActionTruncateTables.NoDbConnection"));
}

Expand Down Expand Up @@ -266,4 +270,36 @@ public boolean isArgFromPrevious() {
public void setArgFromPrevious(boolean argFromPrevious) {
this.argFromPrevious = argFromPrevious;
}

@Override
public void check(
List<ICheckResult> remarks,
WorkflowMeta workflowMeta,
IVariables variables,
IHopMetadataProvider metadataProvider) {

String realConnection = variables.resolve(connection);
if (Utils.isEmpty(realConnection)
|| workflowMeta == null
|| workflowMeta.findDatabase(realConnection, variables) == null) {
String message = BaseMessages.getString(PKG, "ActionTruncateTables.NoDbConnection");
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_WARNING, message, this));
}

if (!argFromPrevious) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] check() warns when no tables are selected, but not when the connection is missing. That is the failure this change fixes at runtime: an action with a table name and an empty connection still passes Verify Workflow and only fails when it runs. workflowMeta is unused, so a connection name that is set but no longer in metadata is also ignored.

Suggestion: When Utils.isEmpty(variables.resolve(connection)), or workflowMeta.findDatabase(...) returns null, add a warning using ActionTruncateTables.NoDbConnection. Do this even when argFromPrevious is set, because previous rows still need a connection.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Updated check() to validate both empty connection and non-existent connection in workflowMeta, showing a warning dialog with NoDbConnection regardless of argFromPrevious.

if (Utils.isEmpty(items)) {
String message =
BaseMessages.getString(PKG, "ActionTruncateTables.CheckResult.NoTablesSelected");
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_WARNING, message, this));
} else {
for (TruncateTableItem item : items) {
if (StringUtils.isEmpty(variables.resolve(item.getTableName()))) {
String message =
BaseMessages.getString(PKG, "ActionTruncateTables.CheckResult.TableNameIsEmpty");
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_WARNING, message, this));
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@

package org.apache.hop.workflow.actions.truncatetables;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.apache.hop.core.Const;
import org.apache.hop.core.database.Database;
import org.apache.hop.core.database.DatabaseMeta;
import org.apache.hop.core.exception.HopDatabaseException;
import org.apache.hop.core.util.Utils;
import org.apache.hop.core.variables.IVariables;
import org.apache.hop.i18n.BaseMessages;
Expand Down Expand Up @@ -302,38 +306,83 @@ private void ok() {
}

private void getTableName() {
DatabaseMeta databaseMeta = getWorkflowMeta().findDatabase(wConnection.getText(), variables);
if (databaseMeta != null) {

try (Database database = new Database(loggingObject, variables, databaseMeta)) {
database.connect();
String[] tableNames = database.getTablenames();
Arrays.sort(tableNames);
EnterSelectionDialog dialog =
new EnterSelectionDialog(
shell,
tableNames,
BaseMessages.getString(PKG, "ActionTruncateTables.SelectTables.Title"),
BaseMessages.getString(PKG, "ActionTruncateTables.SelectTables.Message"));
dialog.setMulti(true);
dialog.setAvoidQuickSearch();
if (dialog.open() != null) {
int[] idx = dialog.getSelectionIndeces();
for (int j : idx) {
TableItem tableItem = new TableItem(wFields.table, SWT.NONE);
tableItem.setText(1, tableNames[j]);
String connectionName = wConnection.getText();
if (Utils.isEmpty(connectionName)) {
MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
mb.setText(BaseMessages.getString(PKG, "System.Dialog.Error.Title"));
mb.setMessage(BaseMessages.getString(PKG, "ActionTruncateTables.NoDbConnection"));
mb.open();
return;
}

DatabaseMeta databaseMeta = getWorkflowMeta().findDatabase(connectionName, variables);
if (databaseMeta == null) {
MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
mb.setText(BaseMessages.getString(PKG, "System.Dialog.Error.Title"));
mb.setMessage(BaseMessages.getString(PKG, "ActionTruncateTables.NoDbConnection"));
mb.open();
return;
}

try (Database database = new Database(loggingObject, variables, databaseMeta)) {
database.connect();
Map<String, Collection<String>> tableMap = database.getTableMap();
List<String> displayList = new ArrayList<>();
List<String[]> schemaTableList = new ArrayList<>();

if (tableMap != null && !tableMap.isEmpty()) {
List<String> schemas = new ArrayList<>(tableMap.keySet());
Collections.sort(schemas, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER));
for (String schema : schemas) {
Collection<String> tableCollection = tableMap.get(schema);
if (tableCollection != null) {
List<String> tables = new ArrayList<>(tableCollection);
Collections.sort(tables, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER));
for (String table : tables) {
String displayName = Utils.isEmpty(schema) ? table : schema + "." + table;
displayList.add(displayName);
schemaTableList.add(new String[] {table, Const.NVL(schema, "")});
}
}
}
} catch (HopDatabaseException e) {
new ErrorDialog(
shell,
BaseMessages.getString(PKG, "System.Dialog.Error.Title"),
BaseMessages.getString(PKG, "ActionTruncateTables.ConnectionError.DialogMessage"),
e);
}
wFields.removeEmptyRows();
wFields.setRowNums();
wFields.optWidth(true);

if (displayList.isEmpty()) {
MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_WARNING);
mb.setText(BaseMessages.getString(PKG, "System.Dialog.Warning.Title"));
mb.setMessage(
BaseMessages.getString(PKG, "ActionTruncateTables.ConnectionError.DialogMessage"));
mb.open();
return;
}

String[] displayArray = displayList.toArray(new String[0]);
EnterSelectionDialog dialog =
new EnterSelectionDialog(
shell,
displayArray,
BaseMessages.getString(PKG, "ActionTruncateTables.SelectTables.Title"),
BaseMessages.getString(PKG, "ActionTruncateTables.SelectTables.Message"));
dialog.setMulti(true);
dialog.setAvoidQuickSearch();
if (dialog.open() != null) {
int[] idx = dialog.getSelectionIndeces();
for (int j : idx) {
String[] st = schemaTableList.get(j);
TableItem tableItem = new TableItem(wFields.table, SWT.NONE);
tableItem.setText(1, st[0]);
tableItem.setText(2, st[1]);
}
}
} catch (Exception e) {
new ErrorDialog(
shell,
BaseMessages.getString(PKG, "System.Dialog.Error.Title"),
BaseMessages.getString(PKG, "ActionTruncateTables.ConnectionError.DialogMessage"),
e);
}
wFields.removeEmptyRows();
wFields.setRowNums();
wFields.optWidth(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#

ActionTruncateTables.ArgEmpty=This argument is empty\!
ActionTruncateTables.CheckResult.NoTablesSelected=No tables selected to truncate.
ActionTruncateTables.CheckResult.TableNameIsEmpty=Table name is empty.
ActionTruncateTables.ConnectionError.DialogMessage=Error\!Can not return table names list\!
ActionTruncateTables.Description=Truncate one or several tables.
ActionTruncateTables.Error.CanNotFindTable=We can not find table [{0}]\!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.hop.workflow.actions.truncatetables;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.hop.core.HopClientEnvironment;
import org.apache.hop.core.Result;
import org.apache.hop.core.logging.HopLogStore;
import org.apache.hop.core.logging.LogLevel;
import org.apache.hop.workflow.Workflow;
import org.apache.hop.workflow.WorkflowMeta;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

class ActionTruncateTablesTest {

@BeforeAll
static void setUp() throws Exception {
HopClientEnvironment.init();
HopLogStore.init();
}

@Test
void testExecuteWithNoConnection() {
ActionTruncateTables action = new ActionTruncateTables();
action.setConnection(null);

Result result = action.execute(new Result(), 0);

assertFalse(result.getResult());
assertEquals(1, result.getNrErrors());
}

@Test
void testExecuteWithNonExistentConnection() {
ActionTruncateTables action = new ActionTruncateTables();
action.setConnection("non-existent-db");

WorkflowMeta workflowMeta = mock(WorkflowMeta.class);
when(workflowMeta.findDatabase(anyString(), any())).thenReturn(null);

Workflow workflow = mock(Workflow.class);
when(workflow.getWorkflowMeta()).thenReturn(workflowMeta);
when(workflow.getLogLevel()).thenReturn(LogLevel.BASIC);

action.setParentWorkflow(workflow);
action.setParentWorkflowMeta(workflowMeta);

Result result = action.execute(new Result(), 0);

assertFalse(result.getResult());
assertEquals(1, result.getNrErrors());
}

@Test
void testCheckRemarks() {
ActionTruncateTables action = new ActionTruncateTables();
action.setConnection(null);

java.util.List<org.apache.hop.core.ICheckResult> remarks = new java.util.ArrayList<>();
WorkflowMeta workflowMeta = mock(WorkflowMeta.class);
when(workflowMeta.findDatabase(any(), any())).thenReturn(null);

org.apache.hop.core.variables.Variables variables =
new org.apache.hop.core.variables.Variables();
action.check(remarks, workflowMeta, variables, null);

assertFalse(remarks.isEmpty());
assertEquals(org.apache.hop.core.ICheckResult.TYPE_RESULT_WARNING, remarks.get(0).getType());
}

@Test
void testCheckRemarksWithArgFromPrevious() {
ActionTruncateTables action = new ActionTruncateTables();
action.setArgFromPrevious(true);
action.setConnection(null);

java.util.List<org.apache.hop.core.ICheckResult> remarks = new java.util.ArrayList<>();
WorkflowMeta workflowMeta = mock(WorkflowMeta.class);

action.check(remarks, workflowMeta, new org.apache.hop.core.variables.Variables(), null);

assertFalse(remarks.isEmpty());
assertEquals(org.apache.hop.core.ICheckResult.TYPE_RESULT_WARNING, remarks.get(0).getType());
}
}
Loading