@Test
void matchingGroupPathAreBlockedPoolMultiSizeParentFirst()
{

    // Check the following setup:
    // Pool A of size 1 with 2 jobs (A1, A2)
    // Pool AB of size 2 with 3 jobs (AB1, AB2, AB3)
    // Order of starting jobs:
    //   - A1
    //   - AB1 && AB2
    //   - A2
    //   - AB3
    GroupedJobInitializer groupedJobInitializer = mock(GroupedJobInitializer.class);
    when(groupedJobInitializer.getPoolSize()).thenReturn(1);
    when(groupedJobInitializer.getDefaultPriority()).thenReturn(Thread.NORM_PRIORITY);
    JobGroupPath jobGroupPathA = new JobGroupPath(Collections.singletonList("A"));
    when(this.groupedJobInitializerManager.getGroupedJobInitializer(eq(jobGroupPathA)))
        .thenReturn(groupedJobInitializer);
    groupedJobInitializer = mock(GroupedJobInitializer.class);
    when(groupedJobInitializer.getPoolSize()).thenReturn(2);
    when(groupedJobInitializer.getDefaultPriority()).thenReturn(Thread.NORM_PRIORITY);
    JobGroupPath jobGroupPathAB = new JobGroupPath(Arrays.asList("A", "B"));
    when(this.groupedJobInitializerManager.getGroupedJobInitializer(eq(jobGroupPathAB)))
        .thenReturn(groupedJobInitializer);
    TestBasicGroupedJob jobA1 = groupedJob("A");
    TestBasicGroupedJob jobA2 = groupedJob("A");
    TestBasicGroupedJob jobAB1 = groupedJob("A", "B");
    TestBasicGroupedJob jobAB2 = groupedJob("A", "B");
    TestBasicGroupedJob jobAB3 = groupedJob("A", "B");
    // Pre-lock all jobs
    jobA1.lock();
    jobA2.lock();
    jobAB1.lock();
    jobAB2.lock();
    jobAB3.lock();
    // Give first jobs to JobExecutor
    this.executor.execute(jobA1);
    // Give enough time for the jobs to be fully taken into ABcount
    waitJobWaiting(jobA1);
    // Give following jobs to JobExecutor (to make sure they are ABtually after since the grouped job executor queue
    // is not "fair")
    this.executor.execute(jobAB1);
    this.executor.execute(jobAB2);
    assertSame(State.WAITING, jobA1.getStatus().getState());
    assertNull(jobA2.getStatus().getState());
    assertNull(jobAB1.getStatus().getState());
    assertNull(jobAB2.getStatus().getState());
    // Next job
    jobA1.unlock();
    waitJobFinished(jobA1);
    // AB1 and AB2 can now start since they were already waiting on a lock
    waitJobWaiting(jobAB1);
    waitJobWaiting(jobAB2);
    // We don't execute A2 at the same time as A1 because in that case A2 is put in the queue of the pool
    // and is not directly waiting on the lock. So in that case it's not deterministic to know which one between
    // AB1 or A2 will get the lock first. To avoid such situation we just wait after AB1 started to start A2.
    this.executor.execute(jobA2);
    // AB1 and AB2 were waiting on the lock: they can start both since the pool is of size 2
    // A2 is now waiting on a lock
    assertSame(State.FINISHED, jobA1.getStatus().getState());
    assertSame(State.WAITING, jobAB1.getStatus().getState());
    assertSame(State.WAITING, jobAB2.getStatus().getState());
    assertNull(jobA2.getStatus().getState());
    // Next job
    jobAB1.unlock();
    waitJobFinished(jobAB1);
    // Start AB3 only now to be sure it does not take the lock before A2.
    this.executor.execute(jobAB3);
    // AB3 cannot start yet even if the pool is of 2 because A2 requested for the lock.
    assertSame(State.FINISHED, jobAB1.getStatus().getState());
    assertSame(State.WAITING, jobAB2.getStatus().getState());
    assertNull(jobAB3.getStatus().getState());
    assertNull(jobA2.getStatus().getState());
    // Next job
    jobAB2.unlock();
    // Once AB2 is finished the lock for A2 is released, it's starting.
    // AB3 is still waiting A2 to release the lock.
    waitJobFinished(jobAB2);
    waitJobWaiting(jobA2);
    assertSame(State.FINISHED, jobAB2.getStatus().getState());
    assertSame(State.WAITING, jobA2.getStatus().getState());
    assertNull(jobAB3.getStatus().getState());
    // Next job
    jobA2.unlock();
    // A2 is finished so AB3 can now take its turn.
    waitJobFinished(jobA2);
    waitJobWaiting(jobAB3);
    assertSame(State.FINISHED, jobA2.getStatus().getState());
    assertSame(State.WAITING, jobAB3.getStatus().getState());
    jobAB3.unlock();
    waitJobFinished(jobAB3);
    assertSame(State.FINISHED, jobAB3.getStatus().getState());
}