Code review comment: I agree that we could de-duplicate some code here. I'm concerned that we're baking in a few assumptions (vertex parallelism should be 1, first vertex in the array is special), and there a few subtle differences in tests that where I don't know whether they are significant or not. (For example, `#testTaskRestoreStateIsNulledAfterDeployment` doesn't allocate a slot beforehand). I don't have the time right now to really look into these things, so I'd move any larger refactoring to this class into a follow-up.

Code under review:
private void testPartitionReleaseAfterFinished(Consumer<Execution> postFinishedExecutionAction) throws Exception {
		final Tuple2<JobID, Collection<ResultPartitionID>> releasedPartitions = Tuple2.of(null, null);
		final SimpleAckingTaskManagerGateway taskManagerGateway = new SimpleAckingTaskManagerGateway();
		taskManagerGateway.setReleasePartitionsConsumer(releasedPartitions::setFields);

		final SimpleSlot slot = new SimpleSlot(
			new SingleSlotTestingSlotOwner(),
			new LocalTaskManagerLocation(),
			0,
			taskManagerGateway);

		final JobVertex producerVertex = createNoOpJobVertex();
		final JobVertex consumerVertex = createNoOpJobVertex();
		consumerVertex.connectNewDataSetAsInput(producerVertex, DistributionPattern.ALL_TO_ALL, ResultPartitionType.BLOCKING);

		final ProgrammedSlotProvider slotProvider = new ProgrammedSlotProvider(1);
		slotProvider.addSlot(producerVertex.getID(), 0, CompletableFuture.completedFuture(slot));

		ExecutionGraph executionGraph = ExecutionGraphTestUtils.createSimpleTestGraph(
			new JobID(),
			slotProvider,
			new NoRestartStrategy(),
			producerVertex,
			consumerVertex);

		executionGraph.start(TestingComponentMainThreadExecutorServiceAdapter.forMainThread());

		ExecutionJobVertex executionJobVertex = executionGraph.getJobVertex(producerVertex.getID());
		ExecutionVertex executionVertex = executionJobVertex.getTaskVertices()[0];

		final Execution execution = executionVertex.getCurrentExecutionAttempt();

		execution.allocateAndAssignSlotForExecution(
			slotProvider,
			false,
			LocationPreferenceConstraint.ALL,
			Collections.emptySet(),
			TestingUtils.infiniteTime());

		execution.deploy();
		execution.switchToRunning();

		
		
		
		execution.markFinished();
		postFinishedExecutionAction.accept(execution);

		assertEquals(executionGraph.getJobID(), releasedPartitions.f0);
		assertEquals(executionVertex.getProducedPartitions().size(), releasedPartitions.f1.size());
		for (ResultPartitionID partitionId : releasedPartitions.f1) {
			IntermediateResultPartition intermediateResultPartition = executionVertex
				.getProducedPartitions()
				.get(partitionId.getPartitionId());
			assertNotNull(intermediateResultPartition);
			assertEquals(execution.getAttemptId(), partitionId.getProducerId());
		}
	}

Line commented on: execution.deploy();

Revised code:
private void testPartitionReleaseAfterFinished(Consumer<Execution> postFinishedExecutionAction) throws Exception {
		final Tuple2<JobID, Collection<ResultPartitionID>> releasedPartitions = Tuple2.of(null, null);
		final SimpleAckingTaskManagerGateway taskManagerGateway = new SimpleAckingTaskManagerGateway();
		taskManagerGateway.setReleasePartitionsConsumer(releasedPartitions::setFields);

		final JobVertex producerVertex = createNoOpJobVertex();
		final JobVertex consumerVertex = createNoOpJobVertex();
		consumerVertex.connectNewDataSetAsInput(producerVertex, DistributionPattern.ALL_TO_ALL, ResultPartitionType.BLOCKING);

		final SimpleSlot slot = new SimpleSlot(
			new SingleSlotTestingSlotOwner(),
			new LocalTaskManagerLocation(),
			0,
			taskManagerGateway);

		final ProgrammedSlotProvider slotProvider = new ProgrammedSlotProvider(1);
		slotProvider.addSlot(producerVertex.getID(), 0, CompletableFuture.completedFuture(slot));

		ExecutionGraph executionGraph = ExecutionGraphTestUtils.createSimpleTestGraph(
			new JobID(),
			slotProvider,
			new NoRestartStrategy(),
			producerVertex,
			consumerVertex);

		executionGraph.start(TestingComponentMainThreadExecutorServiceAdapter.forMainThread());

		ExecutionJobVertex executionJobVertex = executionGraph.getJobVertex(producerVertex.getID());
		ExecutionVertex executionVertex = executionJobVertex.getTaskVertices()[0];

		final Execution execution = executionVertex.getCurrentExecutionAttempt();

		execution.allocateResourcesForExecution(
			slotProvider,
			false,
			LocationPreferenceConstraint.ALL,
			Collections.emptySet(),
			TestingUtils.infiniteTime());

		execution.deploy();
		execution.switchToRunning();

		
		
		
		execution.markFinished();
		postFinishedExecutionAction.accept(execution);

		assertEquals(executionGraph.getJobID(), releasedPartitions.f0);
		assertEquals(executionVertex.getProducedPartitions().size(), releasedPartitions.f1.size());
		for (ResultPartitionID partitionId : releasedPartitions.f1) {
			
			IntermediateResultPartition intermediateResultPartition = executionVertex
				.getProducedPartitions()
				.get(partitionId.getPartitionId());
			assertNotNull(intermediateResultPartition);
			assertEquals(execution.getAttemptId(), partitionId.getProducerId());
		}
	}