package org.ovirt.engine.core.bll.scheduling; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.Collections; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import org.ovirt.engine.core.bll.interfaces.BackendInternal; import org.ovirt.engine.core.bll.scheduling.arem.AffinityRulesEnforcer; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.scheduling.ClusterPolicy; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector; import org.ovirt.engine.core.dao.ClusterDao; import org.ovirt.engine.core.di.InjectorRule; import org.ovirt.engine.core.utils.MockConfigRule; import org.ovirt.engine.core.utils.timer.SchedulerUtilQuartzImpl; @RunWith(MockitoJUnitRunner.class) public class AffinityRulesEnforcementManagerTest { @Rule public MockConfigRule mockConfigRule = new MockConfigRule(); @ClassRule public static InjectorRule injectorRule = new InjectorRule(); @Mock private AuditLogDirector auditLogDirector; @Mock private ClusterDao clusterDao; @Mock private SchedulerUtilQuartzImpl scheduler; @Mock private BackendInternal backend; @Mock private AffinityRulesEnforcer rulesEnforcer; @Mock VM vm1; @Mock VM vm2; @InjectMocks @Spy private AffinityRulesEnforcementManager arem; private Cluster cluster1; private Cluster cluster2; /** * Setup a basic scenario with two clusters: * - vm1 runs on cluster1 * - vm2 runs on cluster2. * In the default setup we tell the AffinityRulesEnforcmenetManager, that in each cluster, something needs to be migrated. */ @Before public void setup() { cluster1 = createCluster(); cluster2 = createCluster(); when(clusterDao.getWithoutMigratingVms()).thenReturn(Arrays.asList(cluster1, cluster2)); when(rulesEnforcer.chooseNextVmToMigrate(eq(cluster1))).thenReturn(vm1); when(rulesEnforcer.chooseNextVmToMigrate(eq(cluster2))).thenReturn(vm2); arem.wakeup(); } protected Cluster createCluster() { Guid id = Guid.newGuid(); Cluster cluster = new Cluster(); cluster.setClusterId(id); cluster.setId(id); cluster.setName("Default cluster"); return cluster; } @Test public void shouldMigrateOneVmPerCluster() { when(rulesEnforcer.chooseNextVmToMigrate(eq(cluster1))).thenReturn(vm1, mock(VM.class), mock(VM.class)); arem.refresh(); verify(arem, times(1)).migrateVM(eq(vm1)); verify(arem, times(1)).migrateVM(eq(vm2)); verify(arem, times(2)).migrateVM(any(VM.class)); } @Test public void shouldNotMigrateVmOnClusterTwoWhileMigrating() { final VM migratingVM = new VM(); migratingVM.setClusterId(cluster2.getId()); when(clusterDao.getWithoutMigratingVms()).thenReturn(Collections.singletonList(cluster1)); arem.refresh(); verify(arem).migrateVM(vm1); verify(arem, times(1)).migrateVM(any(VM.class)); } @Test public void shouldNotMigrateVmOnClusterTwoWhileInUpgradeMode() { cluster2.setClusterPolicyId(ClusterPolicy.UPGRADE_POLICY_GUID); arem.refresh(); verify(arem).migrateVM(vm1); verify(arem, times(1)).migrateVM(any(VM.class)); verify(arem, times(0)).migrateVM(eq(vm2)); } @Test public void shouldNotMigrateVmOnClusterTwoWhenEnforced() { when(rulesEnforcer.chooseNextVmToMigrate(eq(cluster2))).thenReturn(null); arem.refresh(); verify(arem).migrateVM(vm1); verify(arem, times(1)).migrateVM(any(VM.class)); } @Test public void shouldHaveNotingToMigrate() { verify(arem, never()).migrateVM(any(VM.class)); } @Test public void shouldScheduleRegularInterval() { verify(scheduler).scheduleAFixedDelayJob(any(), eq("refresh"), eq(new Class[] {}), eq(new Object[] {}), eq(1L), anyLong(), eq(TimeUnit.MINUTES)); } }