This is an automated email from the ASF dual-hosted git repository.
mcgilman pushed a commit to branch NIFI-15258
in repository https://gitbox.apache.org/repos/asf/nifi-api.git
The following commit(s) were added to refs/heads/NIFI-15258 by this push:
new ca54e76 NIFI-15428: If non-existent property value is set, connector
should be invalid. (#43)
ca54e76 is described below
commit ca54e76f2e5a672e7e90eb07ae802ecadd8738c5
Author: Mark Payne <[email protected]>
AuthorDate: Tue Jan 6 12:05:35 2026 -0500
NIFI-15428: If non-existent property value is set, connector should be
invalid. (#43)
---
.../components/connector/AbstractConnector.java | 27 ++++++++++-
.../connector/TestAbstractConnector.java | 56 +++++++++++++++++++++-
2 files changed, 81 insertions(+), 2 deletions(-)
diff --git
a/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java
b/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java
index 49d8059..8045bc6 100644
--- a/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java
+++ b/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java
@@ -156,7 +156,7 @@ public abstract class AbstractConnector implements
Connector {
* @param flowContext the FlowContext to use for drainage
* @return a CompletableFuture that will be completed when drainage is
complete
*/
- protected CompletableFuture<Void> drainFlowFiles(final FlowContext
flowContext) {
+ public CompletableFuture<Void> drainFlowFiles(final FlowContext
flowContext) {
final CompletableFuture<Void> result = new CompletableFuture<>();
final QueueSize initialQueueSize =
flowContext.getRootGroup().getQueueSize();
if (initialQueueSize.getObjectCount() == 0) {
@@ -454,7 +454,32 @@ public abstract class AbstractConnector implements
Connector {
final String stepName = configurationStep.getName();
final List<ValidationResult> results = new ArrayList<>();
+ // Build a set of all valid property names defined by this
configuration step
final List<ConnectorPropertyGroup> propertyGroups =
configurationStep.getPropertyGroups();
+ final Set<String> validPropertyNames = new HashSet<>();
+ for (final ConnectorPropertyGroup propertyGroup : propertyGroups) {
+ final List<ConnectorPropertyDescriptor> descriptors =
propertyGroup.getProperties();
+ for (final ConnectorPropertyDescriptor descriptor : descriptors) {
+ validPropertyNames.add(descriptor.getName());
+ }
+ }
+
+ // Check for any properties that have been set but are not defined by
this configuration step
+ final Set<String> configuredPropertyNames =
configurationContext.getPropertyNames(stepName);
+ for (final String configuredPropertyName : configuredPropertyNames) {
+ if (!validPropertyNames.contains(configuredPropertyName)) {
+ final String configuredValue =
configurationContext.getProperty(stepName, configuredPropertyName).getValue();
+
+ final ValidationResult invalidResult = new
ValidationResult.Builder()
+ .valid(false)
+ .input(configuredValue)
+ .subject(configuredPropertyName)
+ .explanation("Property '" + configuredPropertyName + "' is
not defined by Connector for Configuration Step '" + stepName + "'")
+ .build();
+ results.add(invalidResult);
+ }
+ }
+
for (final ConnectorPropertyGroup propertyGroup : propertyGroups) {
final List<ConnectorPropertyDescriptor> descriptors =
propertyGroup.getProperties();
final Map<String, ConnectorPropertyDescriptor> descriptorMap =
descriptors.stream()
diff --git
a/src/test/java/org/apache/nifi/components/connector/TestAbstractConnector.java
b/src/test/java/org/apache/nifi/components/connector/TestAbstractConnector.java
index bb77976..20d0534 100644
---
a/src/test/java/org/apache/nifi/components/connector/TestAbstractConnector.java
+++
b/src/test/java/org/apache/nifi/components/connector/TestAbstractConnector.java
@@ -38,6 +38,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -838,10 +839,63 @@ public class TestAbstractConnector {
final List<ValidationResult> results = connector.validate(flowContext,
validationContext);
- assertTrue(results.isEmpty(), "Step 2 should be skipped because
Property With Default has a default value");
+ assertTrue(results.isEmpty(), "Step 2 should be skipped because
Property 'With Default' has a default value");
assertTrue(connector.isCustomValidateCalled());
}
+ @Test
+ void testValidateWithUndefinedPropertiesConfigured() {
+ final ConnectorPropertyDescriptor validProperty = new
ConnectorPropertyDescriptor.Builder()
+ .name("Valid Property")
+ .description("A valid property")
+ .required(true)
+ .build();
+
+ final ConnectorPropertyGroup propertyGroup =
ConnectorPropertyGroup.builder()
+ .name("Test Group")
+ .addProperty(validProperty)
+ .build();
+
+ final ConfigurationStep configStep = new ConfigurationStep.Builder()
+ .name("Test Step")
+ .propertyGroups(List.of(propertyGroup))
+ .build();
+
+ connector.setConfigurationSteps(List.of(configStep));
+
+ // Mock the configuration context to return property names including
multiple undefined properties
+ when(configurationContext.getPropertyNames("Test Step"))
+ .thenReturn(Set.of("Valid Property", "undefined.one",
"undefined.two"));
+
+ final ConnectorPropertyValue validValue =
mock(ConnectorPropertyValue.class);
+ when(validValue.getValue()).thenReturn("valid-value");
+ when(validValue.isSet()).thenReturn(true);
+ when(configurationContext.getProperty("Test Step", "Valid
Property")).thenReturn(validValue);
+
+ final ConnectorPropertyValue undefinedValue =
mock(ConnectorPropertyValue.class);
+ when(undefinedValue.getValue()).thenReturn("some-value");
+ when(undefinedValue.isSet()).thenReturn(true);
+ when(configurationContext.getProperty("Test Step",
"undefined.one")).thenReturn(undefinedValue);
+ when(configurationContext.getProperty("Test Step",
"undefined.two")).thenReturn(undefinedValue);
+
+ final List<ValidationResult> results = connector.validate(flowContext,
validationContext);
+
+ assertEquals(2, results.size());
+
+ // Verify both undefined properties are reported as invalid
+ final List<String> invalidSubjects = results.stream()
+ .map(ValidationResult::getSubject)
+ .toList();
+ assertTrue(invalidSubjects.contains("undefined.one"));
+ assertTrue(invalidSubjects.contains("undefined.two"));
+
+ for (final ValidationResult result : results) {
+ assertFalse(result.isValid());
+ }
+
+ assertFalse(connector.isCustomValidateCalled());
+ }
+
private static class TestableAbstractConnector extends AbstractConnector {
private List<ConfigurationStep> configurationSteps =
Collections.emptyList();
private Collection<ValidationResult> customValidationResults =
Collections.emptyList();