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 @@ -943,12 +943,17 @@ public static boolean isPropertyRenameWithMatchingValue(final FlowDifference dif

/**
* Determines whether a PROPERTY_ADDED difference is an environmental change because the added property is a
* non-dynamic property defined in the component code. Non-dynamic properties are declared through
* {@link ConfigurableComponent#getPropertyDescriptors()} and cannot be added by users. When a PROPERTY_ADDED
* diff exists for such a property, it means the component's code was updated (e.g., via NiFi upgrade or bundle
* version change) and migration added the property. This is an environmental change regardless of whether a
* corresponding BUNDLE_CHANGED diff is present, because the VCI baseline may already have resolved bundles
* (e.g., after {@code discoverCompatibleBundles} during import).
* non-dynamic property defined in the component code that did not exist in the versioned snapshot. Non-dynamic
* properties are declared through {@link ConfigurableComponent#getPropertyDescriptors()} and cannot be added by
* users. When a PROPERTY_ADDED diff exists for such a property and the snapshot did not already define it, it
* means the component's code was updated (e.g., via NiFi upgrade or bundle version change) and migration added
* the property. This is an environmental change regardless of whether a corresponding BUNDLE_CHANGED diff is
* present, because the VCI baseline may already have resolved bundles (e.g., after
* {@code discoverCompatibleBundles} during import).
*
* <p>If the snapshot (component A) already contains a property descriptor for the property in question, the
* property was part of the component definition when the flow was committed and the user has intentionally set
* a value. In that case, this method returns {@code false} so the change is treated as a local modification.</p>
*
* <p>Only Processors and Controller Services are considered because these are the component types that carry
* properties within versioned process groups.</p>
Expand All @@ -969,6 +974,14 @@ private static boolean isPropertyAddedFromMigration(final FlowDifference differe
return false;
}

final VersionedComponent componentA = difference.getComponentA();
if (componentA != null) {
final Map<String, VersionedPropertyDescriptor> descriptorsA = getPropertyDescriptors(componentA);
if (descriptorsA.containsKey(fieldName.get())) {
return false;
}
}

final VersionedComponent componentB = difference.getComponentB();
final ComponentNode componentNode;
if (componentB instanceof InstantiatedVersionedProcessor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,62 @@ public void testPropertyAddedFromMigrationReturnsFalseWhenProcessorNotFound() {
assertFalse(FlowDifferenceFilters.isEnvironmentalChange(difference, null, flowManager));
}

@Test
public void testPropertySetByUserOnProcessorIsNotEnvironmentalChange() {
final FlowManager flowManager = Mockito.mock(FlowManager.class);
final ProcessorNode processorNode = Mockito.mock(ProcessorNode.class);
final ConfigurableComponent configurableComponent = Mockito.mock(ConfigurableComponent.class);

final String propertyName = "Table";
final String instanceId = "processor-instance";

Mockito.when(flowManager.getProcessorNode(instanceId)).thenReturn(processorNode);
Mockito.when(processorNode.getComponent()).thenReturn(configurableComponent);
Mockito.when(configurableComponent.getPropertyDescriptors()).thenReturn(List.of(
new PropertyDescriptor.Builder().name(propertyName).build()));

final VersionedPropertyDescriptor versionedDescriptor = new VersionedPropertyDescriptor();
versionedDescriptor.setName(propertyName);
versionedDescriptor.setDisplayName(propertyName);

final VersionedProcessor registryProcessor = new VersionedProcessor();
registryProcessor.setPropertyDescriptors(Map.of(propertyName, versionedDescriptor));

final InstantiatedVersionedProcessor localProcessor = new InstantiatedVersionedProcessor(instanceId, "group-id");
final FlowDifference difference = new StandardFlowDifference(
DifferenceType.PROPERTY_ADDED, registryProcessor, localProcessor, propertyName, null, "userValue", "Property set by user");

assertFalse(FlowDifferenceFilters.isEnvironmentalChange(difference, null, flowManager));
}

@Test
public void testPropertySetByUserOnControllerServiceIsNotEnvironmentalChange() {
final FlowManager flowManager = Mockito.mock(FlowManager.class);
final ControllerServiceNode controllerServiceNode = Mockito.mock(ControllerServiceNode.class);
final ConfigurableComponent configurableComponent = Mockito.mock(ConfigurableComponent.class);

final String propertyName = "Service Property";
final String instanceId = "service-instance";

Mockito.when(flowManager.getControllerServiceNode(instanceId)).thenReturn(controllerServiceNode);
Mockito.when(controllerServiceNode.getComponent()).thenReturn(configurableComponent);
Mockito.when(configurableComponent.getPropertyDescriptors()).thenReturn(List.of(
new PropertyDescriptor.Builder().name(propertyName).build()));

final VersionedPropertyDescriptor versionedDescriptor = new VersionedPropertyDescriptor();
versionedDescriptor.setName(propertyName);
versionedDescriptor.setDisplayName(propertyName);

final VersionedControllerService registryService = new VersionedControllerService();
registryService.setPropertyDescriptors(Map.of(propertyName, versionedDescriptor));

final InstantiatedVersionedControllerService localService = new InstantiatedVersionedControllerService(instanceId, "group-id");
final FlowDifference difference = new StandardFlowDifference(
DifferenceType.PROPERTY_ADDED, registryService, localService, propertyName, null, "userValue", "Property set by user");

assertFalse(FlowDifferenceFilters.isEnvironmentalChange(difference, null, flowManager));
}

@Test
public void testIsComponentUpdateRequiredForPositionChange() {
final FlowManager flowManager = Mockito.mock(FlowManager.class);
Expand Down
Loading