public Optional<Result> execute( List<RowMetaAndData> rows ) throws KettleException {
    if ( rows.isEmpty() || stopped ) {
      return Optional.empty();
    }

    Trans subtrans = this.createSubtrans();
    running.add( subtrans );
    parentTrans.addActiveSubTransformation( subTransName, subtrans );

    // Pass parameter values
    passParametersToTrans( subtrans, rows.get( 0 ) );

    Result result = new Result();
    result.setRows( rows );
    subtrans.setPreviousResult( result );

    subtrans.prepareExecution( this.parentTrans.getArguments() );
    List<RowMetaAndData> rowMetaAndData = new ArrayList<>();
    subtrans.getSteps().stream()
      .filter( c -> c.step.getStepname().equalsIgnoreCase( subStep ) )
      .findFirst()
      .ifPresent( c -> c.step.addRowListener( new RowAdapter() {
        @Override public void rowWrittenEvent( RowMetaInterface rowMeta, Object[] row ) {
          rowMetaAndData.add( new RowMetaAndData( rowMeta, row ) );
        }
      } ) );
    subtrans.startThreads();

    subtrans.waitUntilFinished();
    updateStatuses( subtrans );
    running.remove( subtrans );

    Result subtransResult = subtrans.getResult();
    subtransResult.setRows( rowMetaAndData  );
    releaseBufferPermits( rows.size() );
    return Optional.of( subtransResult );
  }
@Test
  public void testRunningZeroRowsIsEmptyOptional() throws Exception {
    SubtransExecutor subtransExecutor = new SubtransExecutor( "subtransname", null, null, false, null, "", 0 );
    Optional<Result> execute = subtransExecutor.execute( Collections.emptyList() );
    assertFalse( execute.isPresent() );
  }