@Test
void matchingGroupPathAreBlockedPoolMultiSizeChildrenFirst() throws InterruptedException
{

    // Check the following setup:
    // Pool A of size 2 with 2 jobs (A1, A2)
    // Pool AB of size 2 with 3 jobs (AB1, AB2, AB3)
    // Order of starting jobs:
    //   - AB1 && AB2
    //   - A1 && A2
    //   - AB3
    GroupedJobInitializer groupedJobInitializer = mock(GroupedJobInitializer.class);
    when(groupedJobInitializer.getPoolSize()).thenReturn(2);
    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();
    ////////////////////
    // A/B and A
    this.executor.execute(jobAB1);
    this.executor.execute(jobAB2);
    waitJobWaiting(jobAB1);
    waitJobWaiting(jobAB2);
    this.executor.execute(jobA1);
    // We wait a bit to ensure A1 take the lock before A2.
    Thread.sleep(WAIT_VALUE);
    this.executor.execute(jobA2);
    // AB1 and AB2 are taking all locks, A1 and A2 are waiting the lock to be released.
    assertSame(State.WAITING, jobAB1.getStatus().getState());
    assertSame(State.WAITING, jobAB2.getStatus().getState());
    assertNull(jobA1.getStatus().getState());
    assertNull(jobA2.getStatus().getState());
    jobAB1.unlock();
    waitJobFinished(jobAB1);
    waitJobWaiting(jobA1);
    // Ensure AB3 doesn't take the lock before A2
    this.executor.execute(jobAB3);
    // AB1 is finished so A1 can start right away but A2 is still waiting
    assertSame(State.FINISHED, jobAB1.getStatus().getState());
    assertSame(State.WAITING, jobAB2.getStatus().getState());
    assertSame(State.WAITING, jobA1.getStatus().getState());
    assertNull(jobA2.getStatus().getState());
    assertNull(jobAB3.getStatus().getState());
    jobAB2.unlock();
    // Now that AB2 released the lock, A2 can start too
    waitJobFinished(jobAB2);
    waitJobWaiting(jobA2);
    assertSame(State.FINISHED, jobAB2.getStatus().getState());
    assertSame(State.WAITING, jobA1.getStatus().getState());
    assertSame(State.WAITING, jobA2.getStatus().getState());
    assertNull(jobAB3.getStatus().getState());
    jobA1.unlock();
    jobA2.unlock();
    waitJobFinished(jobA1);
    waitJobFinished(jobA2);
    waitJobWaiting(jobAB3);
    // Now that both A1 and A2 are finished, AB3 can start
    assertSame(State.FINISHED, jobA1.getStatus().getState());
    assertSame(State.FINISHED, jobA2.getStatus().getState());
    assertSame(State.WAITING, jobAB3.getStatus().getState());
    jobAB3.unlock();
    waitJobFinished(jobAB3);
    assertSame(State.FINISHED, jobAB3.getStatus().getState());
}