package org.ovirt.engine.core.bll.gluster; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import org.ovirt.engine.core.bll.utils.GlusterAuditLogUtil; import org.ovirt.engine.core.bll.utils.GlusterUtil; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterSnapshotConfigInfo; import org.ovirt.engine.core.common.businessentities.gluster.GlusterSnapshotStatus; import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotConfig; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotEntity; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; import org.ovirt.engine.core.common.vdscommands.gluster.GlusterVolumeSnapshotVDSParameters; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.dao.ClusterDao; import org.ovirt.engine.core.dao.gluster.GlusterVolumeDao; import org.ovirt.engine.core.dao.gluster.GlusterVolumeSnapshotConfigDao; import org.ovirt.engine.core.dao.gluster.GlusterVolumeSnapshotDao; import org.ovirt.engine.core.utils.lock.EngineLock; @RunWith(MockitoJUnitRunner.class) public class GlusterSnapshotSyncJobTest { private static final Guid CLUSTER_ID_1 = Guid.newGuid(); private static final Guid VOLUME_ID_1 = Guid.newGuid(); private static final String VOLUME_NAME_1 = "VOL1"; private static final Guid VOLUME_ID_2 = Guid.newGuid(); private static final String VOLUME_NAME_2 = "VOL2"; private static final Guid[] existingSnapshotIds = { Guid.newGuid(), Guid.newGuid() }; private static final String[] existingSnapshotNames = { "snap-1", "snap-2" }; private static final Date existingSnapsCreateDate = new Date(); private static final Guid newSnapshotId = Guid.newGuid(); private static final String newSnapshotName = "new-snap"; private static final String PARAM_SNAP_MAX_LIMIT = "snap-max-hard-limit"; @Mock private GlusterVolumeDao volumeDao; @Mock private GlusterVolumeSnapshotDao snapshotDao; @Mock private GlusterVolumeSnapshotConfigDao snapshotConfigDao; @Mock private ClusterDao clusterDao; @InjectMocks @Spy private GlusterSnapshotSyncJob syncJob; @Mock private GlusterAuditLogUtil logUtil; @Mock private GlusterUtil glusterUtil; @Mock private EngineLock engineLock; @Before public void init() { doReturn(getClusters()).when(clusterDao).getAll(); doReturn(getValidCluster()).when(clusterDao).get(any(Guid.class)); doReturn(getVolumes()).when(volumeDao).getByClusterId(CLUSTER_ID_1); doReturn(getServer()).when(glusterUtil).getRandomUpServer(any(Guid.class)); doReturn(engineLock).when(syncJob).acquireVolumeSnapshotLock(any(Guid.class)); } @Test public void testSyncSnapshotsList() { doReturn(getSnapshotVDSReturnVal()).when(syncJob) .runVdsCommand(eq(VDSCommandType.GetGlusterVolumeSnapshotInfo), argThat(snapshotInfoParam())); when(volumeDao.getById(any(Guid.class))).thenReturn(getVolume(CLUSTER_ID_1, VOLUME_ID_1, VOLUME_NAME_1)); syncJob.refreshSnapshotList(); verify(snapshotDao, times(1)).saveAll(anyList()); verify(snapshotDao, times(1)).removeAll(anyList()); verify(snapshotDao, times(1)).updateAllInBatch(anyList()); } @Test public void testSyncSnapshotConfigs() { doReturn(getClusterSnapMaxLimit()).when(snapshotConfigDao) .getConfigByClusterIdAndName(CLUSTER_ID_1, PARAM_SNAP_MAX_LIMIT); doReturn(getVolume(CLUSTER_ID_1, VOLUME_ID_1, VOLUME_NAME_1)).when(volumeDao).getByName(CLUSTER_ID_1, VOLUME_NAME_1); doReturn(getVolume(CLUSTER_ID_1, VOLUME_ID_2, VOLUME_NAME_2)).when(volumeDao).getByName(CLUSTER_ID_1, VOLUME_NAME_2); doReturn(getVolumeSnapMaxLimit()).when(snapshotConfigDao) .getConfigByVolumeIdAndName(CLUSTER_ID_1, VOLUME_ID_1, PARAM_SNAP_MAX_LIMIT); doReturn(getSnapshotConfigVDSReturnValue()).when(syncJob) .runVdsCommand(eq(VDSCommandType.GetGlusterVolumeSnapshotConfigInfo), argThat(snapshotInfoParam())); syncJob.refreshSnapshotConfig(); verify(snapshotConfigDao, times(3)).save(any(GlusterVolumeSnapshotConfig.class)); verify(snapshotConfigDao, times(1)).updateConfigByClusterIdAndName( any(Guid.class), anyString(), anyString()); verify(snapshotConfigDao, times(1)).updateConfigByVolumeIdAndName( any(Guid.class), any(Guid.class), anyString(), anyString()); } private GlusterVolumeSnapshotConfig getClusterSnapMaxLimit() { GlusterVolumeSnapshotConfig param = new GlusterVolumeSnapshotConfig(); param.setClusterId(CLUSTER_ID_1); param.setVolumeId(null); param.setParamName(PARAM_SNAP_MAX_LIMIT); param.setParamValue("256"); return param; } private GlusterVolumeSnapshotConfig getVolumeSnapMaxLimit() { GlusterVolumeSnapshotConfig param = new GlusterVolumeSnapshotConfig(); param.setClusterId(CLUSTER_ID_1); param.setVolumeId(VOLUME_ID_1); param.setParamName(PARAM_SNAP_MAX_LIMIT); param.setParamValue("20"); return param; } private ArgumentMatcher<GlusterVolumeSnapshotVDSParameters> snapshotInfoParam() { return argument -> argument.getClusterId().equals(CLUSTER_ID_1); } private VDSReturnValue getSnapshotConfigVDSReturnValue() { VDSReturnValue vdsRetValue = new VDSReturnValue(); vdsRetValue.setSucceeded(true); vdsRetValue.setReturnValue(getSnapshotConfigInfo()); return vdsRetValue; } private GlusterSnapshotConfigInfo getSnapshotConfigInfo() { GlusterSnapshotConfigInfo config = new GlusterSnapshotConfigInfo(); Map<String, String> clusterConfigs = new HashMap<>(); clusterConfigs.put("snap-max-hard-limit", "200"); clusterConfigs.put("snap-max-soft-limit", "90%"); clusterConfigs.put("auto-delete", "enable"); config.setClusterConfigOptions(clusterConfigs); Map<String, Map<String, String>> volumeConfigs = new HashMap<>(); Map<String, String> volConf1 = new HashMap<>(); volConf1.put("snap-max-hard-limit", "30"); volumeConfigs.put(VOLUME_NAME_1, volConf1); Map<String, String> volConf2 = new HashMap<>(); volConf2.put("snap-max-hard-limit", "50"); volumeConfigs.put(VOLUME_NAME_2, volConf2); config.setVolumeConfigOptions(volumeConfigs); return config; } private VDSReturnValue getSnapshotVDSReturnVal() { VDSReturnValue vdsRetValue = new VDSReturnValue(); vdsRetValue.setSucceeded(true); vdsRetValue.setReturnValue(getSnapshotDetails()); return vdsRetValue; } private List<GlusterVolumeSnapshotEntity> getSnapshotDetails() { List<GlusterVolumeSnapshotEntity> snapshots = new ArrayList<>(); GlusterVolumeSnapshotEntity snap1 = new GlusterVolumeSnapshotEntity(); snap1.setClusterId(CLUSTER_ID_1); snap1.setCreatedAt(existingSnapsCreateDate); snap1.setDescription(""); snap1.setId(existingSnapshotIds[0]); snap1.setSnapshotName(existingSnapshotNames[0]); snap1.setStatus(GlusterSnapshotStatus.DEACTIVATED); snap1.setVolumeId(VOLUME_ID_1); snapshots.add(snap1); GlusterVolumeSnapshotEntity snap2 = new GlusterVolumeSnapshotEntity(); snap2.setClusterId(CLUSTER_ID_1); snap2.setCreatedAt(new Date()); snap2.setDescription(""); snap2.setId(newSnapshotId); snap2.setSnapshotName(newSnapshotName); snap2.setStatus(GlusterSnapshotStatus.ACTIVATED); snap2.setVolumeId(VOLUME_ID_1); snapshots.add(snap2); return snapshots; } private Cluster getValidCluster() { Cluster cluster = new Cluster(); cluster.setId(CLUSTER_ID_1); cluster.setName("cluster"); cluster.setGlusterService(true); cluster.setVirtService(false); cluster.setCompatibilityVersion(Version.v4_0); return cluster; } private List<Cluster> getClusters() { List<Cluster> list = new ArrayList<>(); Cluster cluster = new Cluster(); cluster.setId(CLUSTER_ID_1); cluster.setName("cluster"); cluster.setGlusterService(true); cluster.setVirtService(false); cluster.setCompatibilityVersion(Version.v4_0); list.add(cluster); return list; } private VDS getServer() { VDS vds = new VDS(); vds.setId(Guid.newGuid()); return vds; } private List<GlusterVolumeEntity> getVolumes() { List<GlusterVolumeEntity> volList = new ArrayList<>(); volList.add(getVolume(CLUSTER_ID_1, VOLUME_ID_1, VOLUME_NAME_1)); return volList; } private GlusterVolumeEntity getVolume(Guid clusterId, Guid volumeId, String volumeName) { GlusterVolumeEntity volume = new GlusterVolumeEntity(); volume.setName(volumeName); volume.setClusterId(clusterId); volume.setId(volumeId); volume.setReplicaCount(2); GlusterBrickEntity brick = new GlusterBrickEntity(); brick.setVolumeId(volume.getId()); brick.setBrickDirectory("/export/testvol1"); brick.setStatus(GlusterStatus.UP); brick.setBrickOrder(0); volume.addBrick(brick); GlusterBrickEntity brick2 = new GlusterBrickEntity(); brick2.setVolumeId(volume.getId()); brick2.setBrickDirectory("/export/testvol1"); brick2.setStatus(GlusterStatus.UP); brick2.setBrickOrder(1); volume.addBrick(brick2); return volume; } }