Skip to content
Draft
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 @@ -2193,9 +2193,9 @@ private void updateParameterContext(final ProcessGroup group, final VersionedPro
// Update the Parameter Context
final ParameterContext currentParamContext = group.getParameterContext();
final String proposedParameterContextName = proposed.getParameterContextName();
if (proposedParameterContextName == null && currentParamContext != null) {
group.setParameterContext(null);
} else if (proposedParameterContextName != null) {
// A group's own versioned definition may never carry a Parameter Context if it's meant to be bound locally by
// whatever parent embeds it, so a null name here must not clear an existing binding.
if (proposedParameterContextName != null) {
final VersionedParameterContext versionedParameterContext = versionedParameterContexts.get(proposedParameterContextName);
if (versionedParameterContext != null) {
createMissingParameterProvider(versionedParameterContext, versionedParameterContext.getParameterProvider(), parameterProviderReferences, componentIdGenerator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,39 @@ public void testUpdateParameterContextWhenContextDoesExist() {
verify(processGroup, times(1)).setParameterContext(any(ParameterContext.class));
}

@Test
public void testLocallyAssignedParameterContextPreservedWhenChildGroupUpdatedFromOwnStandaloneVersion() {
// Updating a child group directly to its own standalone version, which never declared a Parameter Context, must not clear a Parameter Context locally assigned to it by a parent.
final ProcessGroup processGroup = mock(ProcessGroup.class);
when(processGroup.getIdentifier()).thenReturn("pg1");
when(processGroup.getPosition()).thenReturn(new org.apache.nifi.connectable.Position(0, 0));
when(processGroup.getFlowFileConcurrency()).thenReturn(FlowFileConcurrency.UNBOUNDED);
when(processGroup.getFlowFileOutboundPolicy()).thenReturn(FlowFileOutboundPolicy.BATCH_OUTPUT);
when(processGroup.getExecutionEngine()).thenReturn(ExecutionEngine.STANDARD);

// A Parameter Context already bound to the child group, simulating a parent's local assignment.
final ParameterContext existingParameterContext = new StandardParameterContext.Builder()
.id("existing-pc")
.name("HTTP ReceiverB")
.parameterReferenceManager(parameterReferenceManager)
.build();
when(processGroup.getParameterContext()).thenReturn(existingParameterContext);

// The child group's own standalone versioned flow definition never had a Parameter Context of its own.
final VersionedProcessGroup rootGroup = new VersionedProcessGroup();
rootGroup.setIdentifier("pg1");
rootGroup.setParameterContextName(null);

final VersionedExternalFlow externalFlow = new VersionedExternalFlow();
externalFlow.setFlowContents(rootGroup);
externalFlow.setParameterContexts(Collections.emptyMap());

synchronizer.synchronize(processGroup, externalFlow, synchronizationOptions);

// The locally-assigned Parameter Context must survive the update.
verify(processGroup, never()).setParameterContext(null);
}

@Test
public void testNewParameterInInheritedContextAddedDuringSync() throws FlowSynchronizationException, InterruptedException, TimeoutException {
// Create P2 with paramA
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,10 @@ private ParameterContextReferenceEntity createReferenceEntity(final String id, f

public ProcessGroupEntity setParameterContext(final String groupId, final ParameterContextEntity parameterContext) throws NiFiClientException, IOException {
final ProcessGroupEntity processGroup = nifiClient.getProcessGroupClient().getProcessGroup(groupId);
processGroup.getComponent().setParameterContext(createReferenceEntity(parameterContext.getId()));
ProcessGroupDTO component = new ProcessGroupDTO();
component.setId(processGroup.getId());
component.setParameterContext(createReferenceEntity(parameterContext.getId()));
processGroup.setComponent(component);
return nifiClient.getProcessGroupClient().updateProcessGroup(processGroup);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -601,4 +601,41 @@ void testApplyParameterContextRecursivelyAcrossVersionedDescendant() throws NiFi
assertNotNull(childAfterUpdate.getComponent().getVersionControlInformation(),
"Versioned child Process Group should remain under version control after a recursive Parameter Context change");
}

/**
* Verifies that a Parameter Context locally assigned to a shared, independently version-controlled child Process Group survives a version upgrade of that child.
*/
@Test
void testLocallyAssignedParameterContextPreservedWhenVersionedChildUpgraded() throws NiFiClientException, IOException, InterruptedException {
final FlowRegistryClientEntity clientEntity = registerClient();
final NiFiClientUtil util = getClientUtil();

final ParameterContextEntity locallyAssignedContext = util.createParameterContext("locally-assigned-context", Map.of(PARAMETER_NAME, PARAMETER_VALUE));

// Shared child Process Group, version-controlled on its own, deliberately without a Parameter Context of its own.
final ProcessGroupEntity versionedGroup = util.createProcessGroup("shared-utility", "root");
//util.setParameterContext(versionedGroup.getId(), emptyContext);
final VersionControlInformationEntity childVciV1 = util.startVersionControl(versionedGroup, clientEntity, TEST_FLOWS_BUCKET, "SharedUtility");

final ProcessGroupEntity instance = util.importFlowFromRegistry("root", childVciV1.getVersionControlInformation());

// Assign a Parameter Context to the child locally, outside its own versioned definition.
util.setParameterContext(instance.getId(), locallyAssignedContext);

// Modify the child's own definition and commit version 2 so there's a newer version to upgrade to.
final ProcessorEntity processor = util.createProcessor(PROCESSOR_TYPE, versionedGroup.getId());
util.setAutoTerminatedRelationships(processor, RELATIONSHIP_SUCCESS);
final ProcessGroupEntity refreshedChildGroup = getNifiClient().getProcessGroupClient().getProcessGroup(versionedGroup.getId());
util.saveFlowVersion(refreshedChildGroup, clientEntity, childVciV1);

// Update the child directly to version 2, fetching its own standalone snapshot which still declares no Parameter Context.
util.changeFlowVersion(instance.getId(), VERSION_2);

final ProcessGroupEntity instanceAfterUpgrade = getNifiClient().getProcessGroupClient().getProcessGroup(instance.getId());
assertEquals(VERSION_2, instanceAfterUpgrade.getComponent().getVersionControlInformation().getVersion());
assertNotNull(instanceAfterUpgrade.getComponent().getParameterContext(),
"Parameter Context locally assigned to the child should survive the version upgrade");
assertEquals(locallyAssignedContext.getId(), instanceAfterUpgrade.getComponent().getParameterContext().getId(),
"Child Process Group should remain bound to the locally-assigned Parameter Context after upgrading to a new version");
}
}
Loading