Piotr Kliczewski has uploaded a new change for review. Change subject: [WIP] engine : 998980 Generic mechanism for update diffs in audit ......................................................................
[WIP] engine : 998980 Generic mechanism for update diffs in audit Mechanism provides audit information about the values modified during update command for DC. Cluster, VM, Template, Storage, Network and Disk. In order to enable command to generate events containing diff it is required to implement UpdateValuesProvider interface. Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=998980 Change-Id: If3362f9bfffe921df44103239ece8348001feca5 Signed-off-by: pkliczewski <piotr.kliczew...@gmail.com> --- M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java M backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java M backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java M backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java M backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties M backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java A backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java M backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java M backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java A backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java M backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java 20 files changed, 597 insertions(+), 112 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/65/20265/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java index 630107e..64e68a0 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java @@ -1,5 +1,10 @@ package org.ovirt.engine.core.bll; +import static org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector.UPDATE_PARAMS; +import static org.ovirt.engine.core.utils.JsonUtils.buildJsonStringFromMaps; +import static org.ovirt.engine.core.utils.ObjectIdentityChecker.GetChangedFields; +import static org.ovirt.engine.core.utils.ObjectIdentityChecker.getValues; + import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -1316,10 +1321,17 @@ return returnValue; } - private void logCommand() { + void logCommand() { Class<?> type = getClass(); InternalCommandAttribute annotation = type.getAnnotation(InternalCommandAttribute.class); if (annotation == null) { + if (UpdateValuesProvider.class.isInstance(this)) { + UpdateValuesProvider<?> provider = (UpdateValuesProvider<?>) this; + List<String> list = GetChangedFields(provider.getOldObject(), provider.getNewObject()); + Map<String, String> oldValues = getValues(provider.getOldObject(), list); + Map<String, String> newValues = getValues(provider.getNewObject(), list); + this.addCustomValue(UPDATE_PARAMS, buildJsonStringFromMaps(list, oldValues, newValues)); + } log(); } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java new file mode 100644 index 0000000..7da4167 --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java @@ -0,0 +1,6 @@ +package org.ovirt.engine.core.bll; + +public interface UpdateValuesProvider<T> { + T getOldObject(); + T getNewObject(); +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java index be33823..942ce28 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java @@ -22,6 +22,8 @@ import org.ovirt.engine.core.common.businessentities.network.Network; import org.ovirt.engine.core.common.businessentities.network.NetworkCluster; import org.ovirt.engine.core.common.businessentities.network.NetworkStatus; +import org.ovirt.engine.core.common.config.Config; +import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.errors.VdcBllMessages; import org.ovirt.engine.core.common.gluster.GlusterFeatureSupported; import org.ovirt.engine.core.common.utils.ListUtils; @@ -34,11 +36,9 @@ import org.ovirt.engine.core.dao.VdsStaticDAO; import org.ovirt.engine.core.dao.network.NetworkDao; import org.ovirt.engine.core.utils.NetworkUtils; -import org.ovirt.engine.core.common.config.Config; -import org.ovirt.engine.core.common.config.ConfigValues; public class UpdateVdsGroupCommand<T extends VdsGroupOperationParameters> extends - VdsGroupOperationCommandBase<T> implements RenamedEntityInfoProvider{ + VdsGroupOperationCommandBase<T> implements RenamedEntityInfoProvider, UpdateValuesProvider<VDSGroup> { private List<VDS> allForVdsGroup; private VDSGroup oldGroup; @@ -384,4 +384,14 @@ public void setEntityId(AuditLogableBase logable) { logable.setVdsGroupId(oldGroup.getId()); } + + @Override + public VDSGroup getOldObject() { + return this.oldGroup; + } + + @Override + public VDSGroup getNewObject() { + return getParameters().getVdsGroup(); + } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java index ed78f79..be7a590 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java @@ -56,7 +56,7 @@ @LockIdNameAttribute public class UpdateVmCommand<T extends VmManagementParametersBase> extends VmManagementCommandBase<T> - implements QuotaVdsDependent, RenamedEntityInfoProvider{ + implements QuotaVdsDependent, RenamedEntityInfoProvider, UpdateValuesProvider<VM> { private VM oldVm; private boolean quotaSanityOnly = false; @@ -530,4 +530,14 @@ return virtioScsiEnabled != null ? virtioScsiEnabled : VmDeviceUtils.isVirtioScsiControllerAttached(getVmId()); } + + @Override + public VM getOldObject() { + return this.oldVm; + } + + @Override + public VM getNewObject() { + return getParameters().getVm(); + } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java index 76fa063..593da63 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java @@ -48,7 +48,7 @@ @LockIdNameAttribute(isReleaseAtEndOfExecute = false) @NonTransactiveCommandAttribute(forceCompensation = true) public class UpdateVmDiskCommand<T extends UpdateVmDiskParameters> extends AbstractDiskVmCommand<T> - implements QuotaStorageDependent { + implements QuotaStorageDependent, UpdateValuesProvider<Disk> { private List<PermissionSubject> listPermissionSubjects; private Map<Guid, List<Disk>> otherVmDisks = new HashMap<Guid, List<Disk>>(); @@ -573,4 +573,14 @@ getReturnValue().getCanDoActionMessages().addAll(internalReturnValue.getCanDoActionMessages()); getReturnValue().setCanDoAction(internalReturnValue.getCanDoAction()); } + + @Override + public Disk getOldObject() { + return getOldDisk(); + } + + @Override + public Disk getNewObject() { + return getNewDisk(); + } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java index 66aeb58..ba400a7 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java @@ -33,7 +33,7 @@ import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector; public class UpdateVmTemplateCommand<T extends UpdateVmTemplateParameters> extends VmTemplateCommand<T> - implements QuotaVdsDependent, RenamedEntityInfoProvider{ + implements QuotaVdsDependent, RenamedEntityInfoProvider, UpdateValuesProvider<VmTemplate> { private VmTemplate mOldTemplate; public UpdateVmTemplateCommand(T parameters) { @@ -245,4 +245,14 @@ return permissionList; } + @Override + public VmTemplate getOldObject() { + return this.mOldTemplate; + } + + @Override + public VmTemplate getNewObject() { + return getParameters().getVmTemplateData(); + } + } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java index 93ca3af..853b552 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java @@ -4,6 +4,7 @@ import org.apache.commons.lang.ObjectUtils; import org.ovirt.engine.core.bll.RenamedEntityInfoProvider; +import org.ovirt.engine.core.bll.UpdateValuesProvider; import org.ovirt.engine.core.bll.ValidationResult; import org.ovirt.engine.core.bll.network.cluster.NetworkClusterHelper; import org.ovirt.engine.core.bll.validator.NetworkValidator; @@ -17,7 +18,8 @@ import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase; import org.ovirt.engine.core.utils.NetworkUtils; -public class UpdateNetworkCommand<T extends AddNetworkStoragePoolParameters> extends NetworkCommon<T> implements RenamedEntityInfoProvider{ +public class UpdateNetworkCommand<T extends AddNetworkStoragePoolParameters> extends NetworkCommon<T> + implements RenamedEntityInfoProvider, UpdateValuesProvider<Network> { private Network oldNetwork; public UpdateNetworkCommand(T parameters) { @@ -143,4 +145,14 @@ public void setEntityId(AuditLogableBase logable) { } + + @Override + public Network getOldObject() { + return getOldNetwork(); + } + + @Override + public Network getNewObject() { + return getParameters().getNetwork(); + } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java index f346203..03224e8 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java @@ -5,9 +5,11 @@ import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.RenamedEntityInfoProvider; +import org.ovirt.engine.core.bll.UpdateValuesProvider; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.StorageDomainManagementParameter; +import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StorageDomainStatic; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.errors.VdcBllMessages; @@ -19,7 +21,7 @@ import org.ovirt.engine.core.utils.ObjectIdentityChecker; public class UpdateStorageDomainCommand<T extends StorageDomainManagementParameter> extends - StorageDomainManagementCommandBase<T> implements RenamedEntityInfoProvider { + StorageDomainManagementCommandBase<T> implements RenamedEntityInfoProvider, UpdateValuesProvider<StorageDomain> { public UpdateStorageDomainCommand(T parameters) { super(parameters); } @@ -115,4 +117,14 @@ public void setEntityId(AuditLogableBase logable) { logable.setStorageDomainId(oldDomain.getId()); } + + @Override + public StorageDomain getOldObject() { + return DbFacade.getInstance().getStorageDomainDao().get(getStorageDomain().getId()); + } + + @Override + public StorageDomain getNewObject() { + return getStorageDomain(); + } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java index 4244341..bc0fc2f 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java @@ -7,6 +7,7 @@ import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; import org.ovirt.engine.core.bll.RenamedEntityInfoProvider; +import org.ovirt.engine.core.bll.UpdateValuesProvider; import org.ovirt.engine.core.bll.utils.VersionSupport; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.VdcObjectType; @@ -37,7 +38,7 @@ @NonTransactiveCommandAttribute public class UpdateStoragePoolCommand<T extends StoragePoolManagementParameter> extends - StoragePoolManagementCommandBase<T> implements RenamedEntityInfoProvider{ + StoragePoolManagementCommandBase<T> implements RenamedEntityInfoProvider, UpdateValuesProvider<StoragePool> { public UpdateStoragePoolCommand(T parameters) { super(parameters); } @@ -267,4 +268,14 @@ public void setEntityId(AuditLogableBase logable) { logable.setStoragePoolId(_oldStoragePool.getId()); } + + @Override + public StoragePool getOldObject() { + return this._oldStoragePool; + } + + @Override + public StoragePool getNewObject() { + return getParameters().getStoragePool(); + } } diff --git a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java index 7870da8..fd5db70 100644 --- a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java +++ b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java @@ -9,14 +9,21 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector.UPDATE_PARAMS; +import static org.ovirt.engine.core.utils.JsonUtils.NEW_VALUE; +import static org.ovirt.engine.core.utils.JsonUtils.OLD_VALUE; +import static org.ovirt.engine.core.utils.JsonUtils.buildTypeFromJson; import static org.ovirt.engine.core.utils.MockConfigRule.mockConfig; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.RandomStringUtils; +import org.codehaus.jackson.type.TypeReference; import org.junit.After; import org.junit.Before; import org.junit.ClassRule; @@ -24,6 +31,7 @@ import org.ovirt.engine.core.bll.session.SessionDataContainer; import org.ovirt.engine.core.bll.tasks.SPMAsyncTaskHandler; import org.ovirt.engine.core.bll.utils.PermissionSubject; +import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.businessentities.DbUser; import org.ovirt.engine.core.common.config.ConfigValues; @@ -76,6 +84,63 @@ @Override protected void logRollbackedTask() { return; + } + + @Override + protected void log() { + // do nothing + } + } + + public class TestObject { + public static final String PARAM_NAME = "name"; + private String name; + + public TestObject(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + private class CommandBaseWithUpdateValues extends CommandBase<VdcActionParametersBase> implements UpdateValuesProvider<TestObject> { + private TestObject oldTestObject = new TestObject("oldValue"); + private TestObject newTestObject = new TestObject("newValue"); + + @Override + public TestObject getOldObject() { + return oldTestObject; + } + + @Override + public TestObject getNewObject() { + return newTestObject; + } + + @Override + protected void executeCommand() { + setSucceeded(true); + } + + @Override + public List<PermissionSubject> getPermissionCheckSubjects() { + return Collections.emptyList(); + } + + @Override + public AuditLogType getAuditLogTypeValue() { + return AuditLogType.USER_UPDATE_VDS; + } + + @Override + protected void log() { + // do nothing } } @@ -207,9 +272,43 @@ } @Test + public void testAuditCommand() { + // given + CommandBase<VdcActionParametersBase> command = new CommandBaseWithUpdateValues(); + + // when + command.logCommand(); + + // then + Map<String, String> values = command.getCustomValues(); + String json = values.get(UPDATE_PARAMS); + assertTrue("Json should be not empty", json != null && !"".equals(json.trim())); + Map<String, Map<String, String>> result = + buildTypeFromJson(json, new TypeReference<HashMap<String, Map<String, String>>>() { + }); + assertTrue("Should be one param", result.get(TestObject.PARAM_NAME) != null); + assertEquals("newValue", result.get(TestObject.PARAM_NAME).get(NEW_VALUE)); + assertEquals("oldValue", result.get(TestObject.PARAM_NAME).get(OLD_VALUE)); + } + + @Test + public void testAuditWithNotUpdateCommand() { + //given + VdcActionParametersBase parameterMock = mock(VdcActionParametersBase.class); + CommandBase<VdcActionParametersBase> command = new CommandBaseDummy(parameterMock); + + // when + command.logCommand(); + + // then + Map<String, String> values = command.getCustomValues(); + assertTrue("Have to be empty", values.isEmpty()); + } + + @Test public void testExtractVariableDeclarationsForStaticMsgs() { VdcActionParametersBase parameterMock = mock(VdcActionParametersBase.class); - CommandBase<VdcActionParametersBase>command = new CommandBaseDummy(parameterMock); + CommandBase<VdcActionParametersBase> command = new CommandBaseDummy(parameterMock); List<String> msgs = Arrays.asList( "ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM", "IRS_FAILED_RETRIEVING_SNAPSHOT_INFO"); @@ -221,10 +320,10 @@ @Test public void testExtractVariableDeclarationsForDynamicMsgs() { VdcActionParametersBase parameterMock = mock(VdcActionParametersBase.class); - CommandBase<VdcActionParametersBase>command = new CommandBaseDummy(parameterMock); + CommandBase<VdcActionParametersBase> command = new CommandBaseDummy(parameterMock); String msg1_1 = "ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM"; String msg1_2 = "$VmName Vm1"; - String msg2 = "IRS_FAILED_CREATING_SNAPSHOT"; + String msg2 = "IRS_FAILED_CREATING_SNAPSHOT"; String msg3_1 = "ACTION_TYPE_FAILED_VM_SNAPSHOT_HAS_NO_CONFIGURATION"; String msg3_2 = "$VmName Vm2"; String msg3_3 = "$SnapshotName Snapshot"; diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java index 1f69f7c..164c3f3 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java @@ -822,6 +822,7 @@ // External tasks USER_ADD_EXTERNAL_JOB(11000), USER_ADD_EXTERNAL_JOB_FAILED(11001), + UPDATE_PARAMS(11002), //network Qos USER_ADDED_NETWORK_QOS(10100), diff --git a/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java b/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java index 13e808a..a90e2aa 100644 --- a/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java +++ b/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java @@ -1,8 +1,10 @@ package org.ovirt.engine.core.compat.backendcompat; +import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -18,16 +20,13 @@ public static List<PropertyInfo> GetProperties(Class<?> type) { List<PropertyInfo> returnValue = new ArrayList<PropertyInfo>(); - try { - PropertyDescriptor[] pds = Introspector.getBeanInfo(type).getPropertyDescriptors(); - for (PropertyDescriptor pd : pds) { - // Class is a bogus property, remove it - if (!CLASS.equals(pd.getName())) { - returnValue.add(new PropertyInfo(pd)); - } + + PropertyDescriptor[] pds = getPropertyDescriptors(type); + for (PropertyDescriptor pd : pds) { + // Class is a bogus property, remove it + if (!CLASS.equals(pd.getName())) { + returnValue.add(new PropertyInfo(pd)); } - } catch (Exception e) { - throw new RuntimeException(e); } return returnValue; } @@ -39,30 +38,63 @@ * @param values - a map which will contains all values of properties */ public static void getPropertyValues(Object obj, Set<String> properties, Map<String, String> values) { - try { - PropertyDescriptor[] pds = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors(); - int hitCount = 0; - for (PropertyDescriptor pd : pds) { - String propertyName = pd.getName().toLowerCase(); - if (properties.contains(propertyName)) { - Object value = null; - hitCount++; - if(!values.containsKey(propertyName)) { - try { - value = pd.getReadMethod().invoke(obj); - String stringValue = value != null ? value.toString() : null; - values.put(propertyName, stringValue); - } catch (Exception e) { - log.warn("Unable to get value of property: " + pd.getDisplayName() + " for class " - + obj.getClass().getName()); - } - } - if (hitCount == properties.size()) { - break; + PropertyDescriptor[] pds = getPropertyDescriptors(obj.getClass()); + int hitCount = 0; + for (PropertyDescriptor pd : pds) { + String propertyName = pd.getName().toLowerCase(); + if (properties.contains(propertyName)) { + Object value = null; + hitCount++; + if(!values.containsKey(propertyName)) { + try { + value = pd.getReadMethod().invoke(obj); + String stringValue = value != null ? value.toString() : null; + values.put(propertyName, stringValue); + } catch (Exception e) { + log.warn("Unable to get value of property: " + pd.getDisplayName() + " for class " + + obj.getClass().getName()); } } + if (hitCount == properties.size()) { + break; + } } - } catch (Exception e) { + } + } + + /** + * Returns values for provided properties and respects the case for property names. + * + * @param obj Source object which contains the values. + * @param properties {@link List} of properties for which values are returned. + * @return {@link Map} of values for properties provided in the list. + */ + public static Map<String, String> getPropertyValues(Object obj, List<String> properties) { + Map<String, String> map = new HashMap<String, String>(); + PropertyDescriptor[] pds = getPropertyDescriptors(obj.getClass()); + int hitCount = 0; + for (PropertyDescriptor pd : pds) { + String propertyName = pd.getName(); + if (properties.contains(propertyName)) { + try { + Object value = pd.getReadMethod().invoke(obj); + map.put(propertyName, value != null ? value.toString() : null); + } catch (Exception e) { + log.warn("Unable to get value of property: " + pd.getDisplayName() + " for class " + + obj.getClass().getName()); + } + if (hitCount == properties.size()) { + break; + } + } + } + return map; + } + + private static PropertyDescriptor[] getPropertyDescriptors(Class<? extends Object> clazz) { + try { + return Introspector.getBeanInfo(clazz).getPropertyDescriptors(); + } catch (IntrospectionException e) { throw new RuntimeException(e); } } diff --git a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java index 85ce98a..b0af050 100644 --- a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java +++ b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java @@ -22,6 +22,7 @@ public final class AuditLogDirector { + public static final String UPDATE_PARAMS = "update_params"; private static final Log log = LogFactory.getLog(AuditLogDirector.class); private static final Map<AuditLogType, String> messages = new EnumMap<AuditLogType, String>(AuditLogType.class); private static final Map<AuditLogType, AuditLogSeverity> severities = @@ -969,7 +970,13 @@ auditLogable.getEventFloodInSec(), auditLogable.getCustomData()); } else if ((message = messages.get(logType)) != null) { // Application log message from AuditLogMessages - resolvedMessage = resolveMessage(message, auditLogable); + String updatedProperties = ""; + if (!auditLogable.getCustomValues().isEmpty()) { + Map<String, String> logMap = new HashMap<>(); + logMap.put(UPDATE_PARAMS, auditLogable.getCustomValue(UPDATE_PARAMS)); + updatedProperties = resolveMessage(messages.get(AuditLogType.UPDATE_PARAMS), logMap); + } + resolvedMessage = resolveMessage(message, auditLogable) + updatedProperties; auditLog = new AuditLog(logType, severity, resolvedMessage, auditLogable.getUserId(), auditLogable.getUserName(), auditLogable.getVmIdRef(), auditLogable.getVmName(), auditLogable.getVdsIdRef(), auditLogable.getVdsName(), auditLogable.getVmTemplateIdRef(), diff --git a/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties b/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties index b167ec3..898c301 100644 --- a/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties +++ b/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties @@ -714,3 +714,4 @@ DISK_ALIGNMENT_SCAN_START=Starting alignment scan of disk '${DiskAlias}'. DISK_ALIGNMENT_SCAN_FAILURE=Alignment scan of disk '${DiskAlias}' failed. DISK_ALIGNMENT_SCAN_SUCCESS=Alignment scan of disk '${DiskAlias}' is complete. +UPDATE_PARAMS= Update parameters are ${update_params}. diff --git a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java index 05769f8..dc41c01 100644 --- a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java +++ b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java @@ -1,87 +1,126 @@ package org.ovirt.engine.core.dal.dbbroker.auditloghandling; -/** - * TODO: - * Commented out test class in order to cancel dependency on PowerMock - * This should be revisited. - */ +import static junit.framework.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.RETURNS_DEFAULTS; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector.UPDATE_PARAMS; +import static org.ovirt.engine.core.utils.ReflectionUtils.setStaticField; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; -import junit.framework.Assert; - +import org.infinispan.Cache; +import org.infinispan.manager.CacheContainer; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.ovirt.engine.core.common.AuditLogType; +import org.ovirt.engine.core.common.businessentities.AuditLog; +import org.ovirt.engine.core.dal.dbbroker.DbFacade; +import org.ovirt.engine.core.dal.dbbroker.DbFacadeLocator; +import org.ovirt.engine.core.dao.AuditLogDAO; +import org.ovirt.engine.core.utils.ejb.BeanProxyType; +import org.ovirt.engine.core.utils.ejb.BeanType; +import org.ovirt.engine.core.utils.ejb.EJBUtilsStrategy; +import org.ovirt.engine.core.utils.ejb.EjbUtils; - -//@RunWith(PowerMockRunner.class) -//@PrepareForTest({ AuditLogDirector.class }) +@RunWith(MockitoJUnitRunner.class) public class AuditLogDirectorTest { -// -// @Mock -// DbFacade dbFacade; -// @Mock -// AuditLogDAO auditLogDao; -// -// @Before -// public void initMocks() { -// initAuditLogDirectorMock(); -// initDbFacadeMock(); -// } -// -// private void initDbFacadeMock() { -// when(dbFacade.getAuditLogDAO()).thenReturn(auditLogDao); -// } -// -// private void initAuditLogDirectorMock() { -// PowerMockito.spy(AuditLogDirector.class); -// PowerMockito.when(AuditLogDirector.getDbFacadeInstance()).thenReturn(dbFacade); -// } -// -// -// /** -// * The test assures that audit loggable objects with timeout, which were created without an explicit log type, with -// * a common key parts, except of the log type, are treated separately.<br> -// * The test invokes two {@Code AuditLogDirector.log()} calls and verifies that each call insert an entry into -// * the database.<br> -// */ - // @Test - // public void testLegalAuditLog() { - // AuditLogableBase logableObject1 = new AuditLogableBase(); - // AuditLogDirector.log(logableObject1, AuditLogType.IRS_DISK_SPACE_LOW); - // - // AuditLogableBase logableObject2 = new AuditLogableBase(); - // AuditLogDirector.log(logableObject2, AuditLogType.IRS_DISK_SPACE_LOW_ERROR); - // Mockito.verify(auditLogDao, Mockito.times(2)).save(Mockito.any(AuditLog.class)); - // } -// -// /** -// * The test assures that audit loggable objects with timeout, which were created without an explicit log type and -// * share the same key are treated in respect to each other by the timeout gaps between events.<br> -// * The test invokes two {@Code AuditLogDirector.log()} calls and verify that only one call inserts an entry -// * into the database. -// */ -// @Test -// public void testIllegalAuditLog() { -// AuditLogableBase logableObject1 = new AuditLogableBase(); -// AuditLogDirector.log(logableObject1, AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME); -// Mockito.verify(auditLogDao, Mockito.times(1)).save(Mockito.any(AuditLog.class)); -// -// AuditLogDirector.log(logableObject1, AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME); -// Mockito.verify(auditLogDao, Mockito.times(1)).save(Mockito.any(AuditLog.class)); -// } -// + + @Mock + private DbFacade dbFacade; + + @Mock + private AuditLogDAO auditLogDao; + + @Mock + private EJBUtilsStrategy strategy; + + @Mock + private CacheContainer cacheContainer; + + @Before + public void setup() throws NoSuchFieldException, SecurityException, IllegalArgumentException, + IllegalAccessException { + when(dbFacade.getAuditLogDao()).thenReturn(auditLogDao); + when(strategy.findBean(BeanType.CACHE_CONTAINER, BeanProxyType.LOCAL)).thenReturn(cacheContainer); + setStaticField(DbFacadeLocator.class, "dbFacade", dbFacade); + setStaticField(EjbUtils.class, "strategy", strategy); + } + + @After + public void tearDown() { + reset(auditLogDao); + } + + /** + * The test assures that audit loggable objects with timeout, which were created without an explicit log type, with + * a common key parts, except of the log type, are treated separately.<br> + * The test invokes two {@Code AuditLogDirector.log()} calls and verifies that each call insert an entry into + * the database.<br> + */ + @Test + public void testLegalAuditLog() { + // given + AuditLogableBase logableObject1 = spy(new AuditLogableBase()); + doReturn(true).when(logableObject1).getLegal(); + AuditLogableBase logableObject2 = spy(new AuditLogableBase()); + doReturn(true).when(logableObject2).getLegal(); + + // when + AuditLogDirector.log(logableObject1, AuditLogType.IRS_DISK_SPACE_LOW); + AuditLogDirector.log(logableObject2, AuditLogType.IRS_DISK_SPACE_LOW_ERROR); + + // then + verify(auditLogDao, times(2)).save(any(AuditLog.class)); + } + + /** + * The test assures that audit loggable objects with timeout, which were created without an explicit log type and + * share the same key are treated in respect to each other by the timeout gaps between events.<br> + * The test invokes two {@Code AuditLogDirector.log()} calls and verify that only one call inserts an entry + * into the database. + */ + @Test + @SuppressWarnings("unchecked") + public void testIllegalAuditLog() { + // given + AuditLogableBase logableObject1 = new AuditLogableBase(); + Cache<Object, Object> cache = mock(Cache.class); + when(cache.putIfAbsent(anyString(), anyString(), anyLong(), any(TimeUnit.class))).thenReturn(logableObject1) + .thenReturn(null); + when(cacheContainer.getCache("timeout-base")).thenReturn(cache); + + // when + AuditLogDirector.log(logableObject1, AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME); + AuditLogDirector.log(logableObject1, AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME); + + // then + verify(auditLogDao, times(1)).save(any(AuditLog.class)); + } + @Test public void testResolveUnknownVariable() { final String message = "This is my ${Variable}"; final String expectedResolved = String.format("This is my %1s", AuditLogDirector.UNKNOWN_VARIABLE_VALUE); Map<String, String> values = Collections.emptyMap(); String resolvedMessage = AuditLogDirector.resolveMessage(message, values); - Assert.assertEquals(expectedResolved, resolvedMessage); + assertEquals(expectedResolved, resolvedMessage); } @Test @@ -90,7 +129,7 @@ final String expectedResolved = "This is my value"; Map<String, String> values = Collections.singletonMap("variable", "value"); String resolvedMessage = AuditLogDirector.resolveMessage(message, values); - Assert.assertEquals(expectedResolved, resolvedMessage); + assertEquals(expectedResolved, resolvedMessage); } @Test @@ -105,7 +144,7 @@ values.put("second", "two"); values.put("blank", " "); String resolvedMessage = AuditLogDirector.resolveMessage(message, values); - Assert.assertEquals(expectedResolved, resolvedMessage); + assertEquals(expectedResolved, resolvedMessage); } @Test @@ -125,6 +164,29 @@ when(logable.getVmName()).thenReturn("TestVM"); String resolvedMessage = AuditLogDirector.resolveMessage(message, logable); - Assert.assertEquals(expectedResolved, resolvedMessage); + assertEquals(expectedResolved, resolvedMessage); + } + + @SuppressWarnings("unchecked") + @Test + public void testAuditUpdate() throws NoSuchFieldException, SecurityException, IllegalArgumentException, + IllegalAccessException { + // given + AuditLogableBase auditLogableBase = mock(AuditLogableBase.class); + when(auditLogableBase.getLegal()).thenReturn(true); + Map<String, String> map = mock(Map.class); + when(map.isEmpty()).thenReturn(false); + when(auditLogableBase.getCustomValues()).thenReturn(map); + when(auditLogableBase.getCustomValue(UPDATE_PARAMS)).thenReturn("{\"propertyName1\":{\"new\":\"value1\",\"old\":\"value2\"}}"); + ArgumentCaptor<AuditLog> captor = ArgumentCaptor.forClass(AuditLog.class); + + // when + AuditLogDirector.log(auditLogableBase, AuditLogType.USER_UPDATE_VDS, ""); + + // then + verify(auditLogDao).save(captor.capture()); + AuditLog log = captor.getValue(); + assertEquals("Host <UNKNOWN> configuration was updated by <UNKNOWN>.Update parameters are {\"propertyName1\":{\"new\":\"value1\",\"old\":\"value2\"}}.", + log.getmessage()); } } diff --git a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java new file mode 100644 index 0000000..cebef4c --- /dev/null +++ b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java @@ -0,0 +1,68 @@ +package org.ovirt.engine.core.utils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; +import org.ovirt.engine.core.utils.log.Log; +import org.ovirt.engine.core.utils.log.LogFactory; + +public class JsonUtils { + + public final static String NEW_VALUE = "new"; + + public final static String OLD_VALUE = "old"; + + private static Log log = LogFactory.getLog(JsonUtils.class); + + /** + * Builds json string from properties provided in the list and new and old values provide in the maps. Json example: + * <code>{"propertyName1":{"new":"value1","old":"value2"},"propertyName2":{"new":"value1","old":"value2"}}</code> + * + * @param properties + * {@link List} with properties + * @param oldMap + * {@link Map} containing old values for the properties + * @param newMap + * {@link Map} containing new values for the properties + * @return Json string like in the example. + */ + public static String buildJsonStringFromMaps(List<String> properties, + Map<String, String> oldMap, + Map<String, String> newMap) { + + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(prepareJsonMap(properties, oldMap, newMap)); + } catch (IOException e) { + log.warn("JsonUtils :: buildJsonStringFromMaps unable to marshall map to json"); + return ""; + } + } + + public static <T> T buildTypeFromJson(String json, TypeReference<T> typeReference) { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(json, typeReference); + } catch (IOException e) { + log.warn("JsonUtils :: buildTypeFromJson unable to marshall json to type"); + return null; + } + } + + private static Map<String, Map<String, String>> prepareJsonMap(List<String> properties, + Map<String, String> oldMap, + Map<String, String> newMap) { + Map<String, Map<String, String>> map = new HashMap<>(); + for (String property : properties) { + Map<String, String> propertyMap = new HashMap<>(); + propertyMap.put(OLD_VALUE, oldMap.get(property)); + propertyMap.put(NEW_VALUE, newMap.get(property)); + map.put(property, propertyMap); + } + return map; + } +} diff --git a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java index a009719..9aa8685 100644 --- a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java +++ b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java @@ -194,6 +194,10 @@ return returnValue; } + public static Map<String, String> getValues(Object source, List<String> properties){ + return TypeCompat.getPropertyValues(source, properties); + } + /** * Logs the error. * diff --git a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java index 708ecae..a572afc 100644 --- a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java +++ b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java @@ -1,6 +1,7 @@ package org.ovirt.engine.core.utils; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; @@ -89,4 +90,18 @@ throw new IllegalStateException(e); } } + + /** + * Replace an object in static filed for provided class. + * + * @param clazz Class holds static field. + * @param fieldName Name of the field to be replaced. + * @param newObject Object which is used as replacement. + */ + public static void setStaticField(Class<?> clazz, String fieldName, Object newObject) throws NoSuchFieldException, + SecurityException, IllegalArgumentException, IllegalAccessException { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(null, newObject); + } } diff --git a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java new file mode 100644 index 0000000..6c79a77 --- /dev/null +++ b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java @@ -0,0 +1,82 @@ +package org.ovirt.engine.core.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.ovirt.engine.core.utils.JsonUtils.NEW_VALUE; +import static org.ovirt.engine.core.utils.JsonUtils.OLD_VALUE; +import static org.ovirt.engine.core.utils.JsonUtils.buildJsonStringFromMaps; +import static org.ovirt.engine.core.utils.JsonUtils.buildTypeFromJson; +import static org.ovirt.engine.core.utils.ObjectIdentityChecker.GetChangedFields; +import static org.ovirt.engine.core.utils.ObjectIdentityChecker.getValues; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.type.TypeReference; +import org.junit.Test; + +public class JsonUtilsTest { + + @Test + public void testBuildingJsonFromMaps() throws JsonParseException, JsonMappingException, IOException { + // given + Jedi jedi1 = new Jedi(); + Jedi jedi2 = new Jedi(); + jedi2.saberColor = "red"; + List<String> changes = GetChangedFields(jedi1, jedi2); + + // when + String json = buildJsonStringFromMaps(changes, getValues(jedi1, changes), getValues(jedi2, changes)); + + // then + Map<String, Map<String, String>> result = + buildTypeFromJson(json, new TypeReference<HashMap<String, Map<String, String>>>() { + }); + assertTrue("Map should have only one property", result.keySet().size() == 1); + assertEquals("red", result.get("saberColor").get(NEW_VALUE)); + assertEquals("Blue", result.get("saberColor").get(OLD_VALUE)); + } + + @Test + public void testBuildingJsonFromMapsWithMultipleProperties() throws JsonParseException, JsonMappingException, + IOException { + // given + Jedi jedi1 = new Jedi(); + jedi1.name = "Yoda"; + Jedi jedi2 = new Jedi(); + jedi2.saberColor = "red"; + List<String> changes = GetChangedFields(jedi1, jedi2); + + // when + String json = buildJsonStringFromMaps(changes, getValues(jedi1, changes), getValues(jedi2, changes)); + + // then + Map<String, Map<String, String>> result = + buildTypeFromJson(json, new TypeReference<HashMap<String, Map<String, String>>>() { + }); + assertTrue("Map should have two properties", result.keySet().size() == 2); + assertEquals("red", result.get("saberColor").get(NEW_VALUE)); + assertEquals("Yoda", result.get("name").get(OLD_VALUE)); + } + + @Test + public void testBuildingJsonFromPamsWithNoChanges() throws JsonParseException, JsonMappingException, IOException { + // given + Jedi jedi1 = new Jedi(); + Jedi jedi2 = new Jedi(); + List<String> changes = GetChangedFields(jedi1, jedi2); + + // when + String json = buildJsonStringFromMaps(changes, getValues(jedi1, changes), getValues(jedi2, changes)); + + // then + Map<String, Map<String, String>> result = + buildTypeFromJson(json, new TypeReference<HashMap<String, Map<String, String>>>() { + }); + assertTrue("Map should have no properties", result.keySet().isEmpty()); + } +} diff --git a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java index cdd01b6..6092687 100644 --- a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java +++ b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java @@ -1,10 +1,12 @@ package org.ovirt.engine.core.utils; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.List; +import java.util.Map; import org.junit.Test; @@ -48,4 +50,23 @@ changed = oic.IsFieldsUpdated(jedi1, jedi2, Arrays.asList("saberColor")); assertTrue("1 Change", changed); } + + @Test + public void testValuesUpdated() { + // given + Jedi jedi1 = new Jedi(); + Jedi jedi2 = new Jedi(); + jedi2.saberColor = "red"; + List<String> changes = ObjectIdentityChecker.GetChangedFields(jedi1, jedi2); + + // when + Map<String, String> oldValues = ObjectIdentityChecker.getValues(jedi1, changes); + Map<String, String> newValues = ObjectIdentityChecker.getValues(jedi2, changes); + + // then + assertTrue("Should be 1 value", oldValues.size() == 1); + assertEquals("Blue", oldValues.get("saberColor")); + assertTrue("Should be 1 value", newValues.size() == 1); + assertEquals("red", newValues.get("saberColor")); + } } -- To view, visit http://gerrit.ovirt.org/20265 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If3362f9bfffe921df44103239ece8348001feca5 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Piotr Kliczewski <piotr.kliczew...@gmail.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches