From 78dc833d14a1d591aa29968c253b91dfbccf15ac Mon Sep 17 00:00:00 2001 From: Luca Frosini Date: Fri, 9 Oct 2015 12:52:42 +0000 Subject: [PATCH] Merged from branch git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/accounting/accounting-lib@119574 82a268e6-3cf1-43bd-a215-b396298e98cf --- .../datamodel/BasicUsageRecord.java | 1 + .../accounting/datamodel/RawUsageRecord.java | 85 +++---------------- .../MoveToCreationTime.java | 16 ++++ .../MoveToCreationTimeAction.java | 36 ++++++++ .../backwardcompatibility/MoveToScope.java | 16 ++++ .../MoveToScopeAction.java | 22 +++++ .../MoveToUsageRecordType.java | 16 ++++ .../MoveToUsageRecordTypeAction.java | 29 +++++++ .../basetypes/AbstractStorageUsageRecord.java | 6 +- .../validators/DeprecatedWarningAction.java | 2 +- .../annotations/FixDataVolumeSign.java | 23 +++++ .../validators/FixDataVolumeSignAction.java | 77 +++++++++++++++++ .../persistence/AccountingPersistence.java | 4 +- .../usagerecords/StorageUsageRecordTest.java | 18 +++- 14 files changed, 270 insertions(+), 81 deletions(-) create mode 100644 src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTime.java create mode 100644 src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTimeAction.java create mode 100644 src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScope.java create mode 100644 src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScopeAction.java create mode 100644 src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordType.java create mode 100644 src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordTypeAction.java create mode 100644 src/main/java/org/gcube/accounting/datamodel/validations/annotations/FixDataVolumeSign.java create mode 100644 src/main/java/org/gcube/accounting/datamodel/validations/validators/FixDataVolumeSignAction.java diff --git a/src/main/java/org/gcube/accounting/datamodel/BasicUsageRecord.java b/src/main/java/org/gcube/accounting/datamodel/BasicUsageRecord.java index ffdfd10..5fa336d 100644 --- a/src/main/java/org/gcube/accounting/datamodel/BasicUsageRecord.java +++ b/src/main/java/org/gcube/accounting/datamodel/BasicUsageRecord.java @@ -162,6 +162,7 @@ public abstract class BasicUsageRecord implements UsageRecord, Serializable { try { validator = managedClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { + logger.error("{} {}", keyString, annotation, e); continue; } fieldValidators.add(validator); diff --git a/src/main/java/org/gcube/accounting/datamodel/RawUsageRecord.java b/src/main/java/org/gcube/accounting/datamodel/RawUsageRecord.java index abe7597..a4e244b 100644 --- a/src/main/java/org/gcube/accounting/datamodel/RawUsageRecord.java +++ b/src/main/java/org/gcube/accounting/datamodel/RawUsageRecord.java @@ -4,23 +4,20 @@ package org.gcube.accounting.datamodel; import java.io.Serializable; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; +import org.gcube.accounting.datamodel.backwardcompatibility.MoveToCreationTime; +import org.gcube.accounting.datamodel.backwardcompatibility.MoveToScope; +import org.gcube.accounting.datamodel.backwardcompatibility.MoveToUsageRecordType; +import org.gcube.accounting.datamodel.deprecationmanagement.annotations.DeprecatedWarning; import org.gcube.accounting.datamodel.usagerecords.JobUsageRecord; import org.gcube.accounting.datamodel.usagerecords.PortletUsageRecord; import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord; import org.gcube.accounting.datamodel.usagerecords.StorageUsageRecord; import org.gcube.accounting.datamodel.usagerecords.TaskUsageRecord; -import org.gcube.accounting.datamodel.decorators.FieldAction; -import org.gcube.accounting.datamodel.decorators.FieldDecorator; -import org.gcube.accounting.datamodel.deprecationmanagement.annotations.DeprecatedWarning; import org.gcube.accounting.datamodel.validations.annotations.NotEmpty; import org.gcube.accounting.datamodel.validations.annotations.NotEmptyIfNotNull; import org.gcube.accounting.exception.InvalidValueException; @@ -44,22 +41,6 @@ public class RawUsageRecord extends BasicUsageRecord implements SingleUsageRecor @DeprecatedWarning @MoveToScope @NotEmpty public static final String RESOURCE_SCOPE = "resourceScope"; - @Target(ElementType.FIELD) - @Retention(RetentionPolicy.RUNTIME) - @FieldDecorator(managed=MoveToScopeAction.class) - protected @interface MoveToScope { } - protected class MoveToScopeAction implements FieldAction { - @Override - public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { - if(value instanceof String){ - usageRecord.setScope((String) value); - }else{ - throw new InvalidValueException(); - } - return value; - } - } - @DeprecatedWarning @NotEmptyIfNotNull public static final String CREATOR_ID = "creatorId"; @@ -69,35 +50,7 @@ public class RawUsageRecord extends BasicUsageRecord implements SingleUsageRecor @DeprecatedWarning @MoveToCreationTime protected static final String CREATE_TIME = "createTime"; - @Target(ElementType.FIELD) - @Retention(RetentionPolicy.RUNTIME) - @FieldDecorator(managed=MoveToCreationTimeAction.class) - protected @interface MoveToCreationTime { } - protected class MoveToCreationTimeAction implements FieldAction { - @Override - public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { - if(value instanceof Date){ - Calendar calendar = Calendar.getInstance(); - calendar.setTime((Date) value); - value = calendar; - } - if(value instanceof Long){ - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis((Long) value); - value = calendar; - } - - if(value instanceof Calendar){ - usageRecord.setCreationTime((Calendar) value); - }else{ - throw new InvalidValueException(); - } - - return value; - } - } - - private final static Map resourceTypeMapping; + public final static Map resourceTypeMapping; private final static String JOB = "job"; private final static String TASK = "task"; @@ -117,31 +70,15 @@ public class RawUsageRecord extends BasicUsageRecord implements SingleUsageRecor @DeprecatedWarning @MoveToUsageRecordType protected static final String RESOURCE_TYPE = "resourceType"; - @Target(ElementType.FIELD) - @Retention(RetentionPolicy.RUNTIME) - @FieldDecorator(managed=MoveToUsageRecordTypeAction.class) - protected @interface MoveToUsageRecordType { } - protected class MoveToUsageRecordTypeAction implements FieldAction { - - @Override - public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { - if(value instanceof String){ - String newValue = resourceTypeMapping.get(value); - if(newValue == null){ - throw new InvalidValueException(); - } - resourceProperties.put(USAGE_RECORD_TYPE, newValue); - }else{ - throw new InvalidValueException(); - } - return value; - } - } - @DeprecatedWarning //@MoveToAggregatedUsageRecordId protected static final String AGGREGATED_ID = "aggregatedId"; + /** + * Redeclared to allow @MoveToUsageRecordTypeAction to access it + */ + public static final String USAGE_RECORD_TYPE = BasicUsageRecord.USAGE_RECORD_TYPE; + /* @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @@ -265,7 +202,7 @@ public class RawUsageRecord extends BasicUsageRecord implements SingleUsageRecor calendar.setTime(createTime); setCreationTime(calendar); */ - logger.warn("The method is deprecated. Please modify your code as soon as possible"); + //logger.warn("The method is deprecated. Please modify your code as soon as possible"); } diff --git a/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTime.java b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTime.java new file mode 100644 index 0000000..f702b6d --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTime.java @@ -0,0 +1,16 @@ +/** + * + */ +package org.gcube.accounting.datamodel.backwardcompatibility; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.gcube.accounting.datamodel.decorators.FieldDecorator; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@FieldDecorator(managed=MoveToCreationTimeAction.class) +public @interface MoveToCreationTime { } \ No newline at end of file diff --git a/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTimeAction.java b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTimeAction.java new file mode 100644 index 0000000..cdc8e52 --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToCreationTimeAction.java @@ -0,0 +1,36 @@ +/** + * + */ +package org.gcube.accounting.datamodel.backwardcompatibility; + +import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; + +import org.gcube.accounting.datamodel.UsageRecord; +import org.gcube.accounting.datamodel.decorators.FieldAction; +import org.gcube.accounting.exception.InvalidValueException; + +public class MoveToCreationTimeAction implements FieldAction { + @Override + public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { + if(value instanceof Date){ + Calendar calendar = Calendar.getInstance(); + calendar.setTime((Date) value); + value = calendar; + } + if(value instanceof Long){ + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis((Long) value); + value = calendar; + } + + if(value instanceof Calendar){ + usageRecord.setCreationTime((Calendar) value); + }else{ + throw new InvalidValueException(); + } + + return value; + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScope.java b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScope.java new file mode 100644 index 0000000..a974476 --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScope.java @@ -0,0 +1,16 @@ +/** + * + */ +package org.gcube.accounting.datamodel.backwardcompatibility; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.gcube.accounting.datamodel.decorators.FieldDecorator; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@FieldDecorator(managed=MoveToScopeAction.class) +public @interface MoveToScope { } \ No newline at end of file diff --git a/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScopeAction.java b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScopeAction.java new file mode 100644 index 0000000..6b7005d --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToScopeAction.java @@ -0,0 +1,22 @@ +/** + * + */ +package org.gcube.accounting.datamodel.backwardcompatibility; + +import java.io.Serializable; + +import org.gcube.accounting.datamodel.UsageRecord; +import org.gcube.accounting.datamodel.decorators.FieldAction; +import org.gcube.accounting.exception.InvalidValueException; + +public class MoveToScopeAction implements FieldAction { + @Override + public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { + if(value instanceof String){ + usageRecord.setScope((String) value); + }else{ + throw new InvalidValueException(); + } + return value; + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordType.java b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordType.java new file mode 100644 index 0000000..15e1cea --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordType.java @@ -0,0 +1,16 @@ +/** + * + */ +package org.gcube.accounting.datamodel.backwardcompatibility; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.gcube.accounting.datamodel.decorators.FieldDecorator; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@FieldDecorator(managed=MoveToUsageRecordTypeAction.class) +public @interface MoveToUsageRecordType { } \ No newline at end of file diff --git a/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordTypeAction.java b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordTypeAction.java new file mode 100644 index 0000000..b3479a4 --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/backwardcompatibility/MoveToUsageRecordTypeAction.java @@ -0,0 +1,29 @@ +/** + * + */ +package org.gcube.accounting.datamodel.backwardcompatibility; + +import java.io.Serializable; + +import org.gcube.accounting.datamodel.RawUsageRecord; +import org.gcube.accounting.datamodel.UsageRecord; +import org.gcube.accounting.datamodel.decorators.FieldAction; +import org.gcube.accounting.exception.InvalidValueException; + +@SuppressWarnings("deprecation") +public class MoveToUsageRecordTypeAction implements FieldAction { + + @Override + public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { + if(value instanceof String){ + String newValue = RawUsageRecord.resourceTypeMapping.get(value); + if(newValue == null){ + throw new InvalidValueException(); + } + usageRecord.setResourceProperty(RawUsageRecord.USAGE_RECORD_TYPE, newValue); + }else{ + throw new InvalidValueException(); + } + return value; + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/accounting/datamodel/basetypes/AbstractStorageUsageRecord.java b/src/main/java/org/gcube/accounting/datamodel/basetypes/AbstractStorageUsageRecord.java index c8f0eae..05a1934 100644 --- a/src/main/java/org/gcube/accounting/datamodel/basetypes/AbstractStorageUsageRecord.java +++ b/src/main/java/org/gcube/accounting/datamodel/basetypes/AbstractStorageUsageRecord.java @@ -9,6 +9,7 @@ import java.util.Map; import org.gcube.accounting.datamodel.BasicUsageRecord; import org.gcube.accounting.datamodel.decorators.RequiredField; +import org.gcube.accounting.datamodel.validations.annotations.FixDataVolumeSign; import org.gcube.accounting.datamodel.validations.annotations.NotEmpty; import org.gcube.accounting.datamodel.validations.annotations.NotEmptyIfNotNull; import org.gcube.accounting.datamodel.validations.annotations.ValidDataType; @@ -79,7 +80,7 @@ public abstract class AbstractStorageUsageRecord extends BasicUsageRecord { * The value is a controlled dictionary by * {@link #StorageUsageRecord.OperationType} */ - @RequiredField @ValidOperationType + @RequiredField @ValidOperationType @FixDataVolumeSign public static final String OPERATION_TYPE = "operationType"; /** * KEY for : type of data accessed. @@ -92,10 +93,9 @@ public abstract class AbstractStorageUsageRecord extends BasicUsageRecord { /** * Quantity of data in terms of KB */ - @RequiredField @ValidLong + @RequiredField @ValidLong @FixDataVolumeSign public static final String DATA_VOLUME = "dataVolume"; - /** * KEY for : Qualifies the data in terms of data (e.g. MIME type for the * Storage, domain for a database) diff --git a/src/main/java/org/gcube/accounting/datamodel/deprecationmanagement/validators/DeprecatedWarningAction.java b/src/main/java/org/gcube/accounting/datamodel/deprecationmanagement/validators/DeprecatedWarningAction.java index 1656138..b790238 100644 --- a/src/main/java/org/gcube/accounting/datamodel/deprecationmanagement/validators/DeprecatedWarningAction.java +++ b/src/main/java/org/gcube/accounting/datamodel/deprecationmanagement/validators/DeprecatedWarningAction.java @@ -24,7 +24,7 @@ public class DeprecatedWarningAction implements FieldAction { */ @Override public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { - logger.warn("The field {} is deprecated for {}. Anyway the field will be included in the document", + logger.trace("The field {} is deprecated for {}. Anyway the field will be included in the document", key, usageRecord.getClass().getSimpleName()); return value; } diff --git a/src/main/java/org/gcube/accounting/datamodel/validations/annotations/FixDataVolumeSign.java b/src/main/java/org/gcube/accounting/datamodel/validations/annotations/FixDataVolumeSign.java new file mode 100644 index 0000000..923212d --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/validations/annotations/FixDataVolumeSign.java @@ -0,0 +1,23 @@ +/** + * + */ +package org.gcube.accounting.datamodel.validations.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.gcube.accounting.datamodel.decorators.FieldDecorator; +import org.gcube.accounting.datamodel.validations.validators.FixDataVolumeSignAction; + +/** + * @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/ + * + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@FieldDecorator(managed=FixDataVolumeSignAction.class) +public @interface FixDataVolumeSign { + +} diff --git a/src/main/java/org/gcube/accounting/datamodel/validations/validators/FixDataVolumeSignAction.java b/src/main/java/org/gcube/accounting/datamodel/validations/validators/FixDataVolumeSignAction.java new file mode 100644 index 0000000..c60e9ea --- /dev/null +++ b/src/main/java/org/gcube/accounting/datamodel/validations/validators/FixDataVolumeSignAction.java @@ -0,0 +1,77 @@ +/** + * + */ +package org.gcube.accounting.datamodel.validations.validators; + +import java.io.Serializable; + +import org.gcube.accounting.datamodel.UsageRecord; +import org.gcube.accounting.datamodel.basetypes.AbstractStorageUsageRecord; +import org.gcube.accounting.datamodel.basetypes.AbstractStorageUsageRecord.OperationType; +import org.gcube.accounting.datamodel.decorators.FieldAction; +import org.gcube.accounting.exception.InvalidValueException; + +/** + * @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/ + * + */ +public class FixDataVolumeSignAction implements FieldAction { + + protected Long checkIt(Long dataVolume, OperationType operationType){ + switch (operationType) { + case CREATE:{ + dataVolume = (dataVolume > 0) ? dataVolume : -dataVolume; + break; + } + case READ:{ + dataVolume = (dataVolume > 0) ? dataVolume : -dataVolume; + break; + } + case UPDATE:{ + break; + } + case DELETE:{ + dataVolume = (dataVolume < 0) ? dataVolume : -dataVolume; + break; + } + default:{ + break; + } + } + + return dataVolume; + } + + /** + * {@inheritDoc} + */ + @Override + public Serializable validate(String key, Serializable value, UsageRecord usageRecord) throws InvalidValueException { + try { + + if(key.compareTo(AbstractStorageUsageRecord.DATA_VOLUME)==0){ + OperationType operationType = (OperationType) usageRecord.getResourceProperty(AbstractStorageUsageRecord.OPERATION_TYPE); + if(operationType!=null){ + ValidLongValidator validLongValidator = new ValidLongValidator(); + value = validLongValidator.validate(key, value, usageRecord); + Long dataVolume = new Long((Long) value); + value = checkIt(dataVolume, operationType); + } + } + + if(key.compareTo(AbstractStorageUsageRecord.OPERATION_TYPE)==0){ + Long dataVolume = (Long) usageRecord.getResourceProperty(AbstractStorageUsageRecord.DATA_VOLUME); + if(dataVolume!=null){ + ValidOperationTypeValidator v = new ValidOperationTypeValidator(); + value = v.validate(key, value, usageRecord); + OperationType operationType = (OperationType) value; + Long newDataVolume = checkIt(dataVolume, operationType); + usageRecord.setResourceProperty(AbstractStorageUsageRecord.DATA_VOLUME, newDataVolume); + } + } + + + }catch(InvalidValueException e){ } + return value; + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/accounting/persistence/AccountingPersistence.java b/src/main/java/org/gcube/accounting/persistence/AccountingPersistence.java index 69b91ae..c87b79b 100644 --- a/src/main/java/org/gcube/accounting/persistence/AccountingPersistence.java +++ b/src/main/java/org/gcube/accounting/persistence/AccountingPersistence.java @@ -79,12 +79,12 @@ public abstract class AccountingPersistence { String fallabackPersistenceName = fallback.getClass().getSimpleName(); try { logger.error("{} was not accounted succesfully from {}. Trying to use {}.", - usageRecord.toString(), persistenceName, fallabackPersistenceName); + usageRecord.toString(), persistenceName, fallabackPersistenceName, e); fallback.reallyAccount(usageRecord); logger.debug("{} accounted succesfully from {}", usageRecord.toString(), fallabackPersistenceName); }catch(Exception ex){ - logger.error("{} was not accounted at all", usageRecord.toString()); + logger.error("{} was not accounted at all", usageRecord.toString(), e); } } } diff --git a/src/test/java/org/gcube/accounting/datamodel/usagerecords/StorageUsageRecordTest.java b/src/test/java/org/gcube/accounting/datamodel/usagerecords/StorageUsageRecordTest.java index 076e137..fda8254 100644 --- a/src/test/java/org/gcube/accounting/datamodel/usagerecords/StorageUsageRecordTest.java +++ b/src/test/java/org/gcube/accounting/datamodel/usagerecords/StorageUsageRecordTest.java @@ -8,18 +8,23 @@ import java.util.Set; import org.gcube.accounting.datamodel.BasicUsageRecord; import org.gcube.accounting.datamodel.BasicUsageRecordUtility; +import org.gcube.accounting.datamodel.basetypes.AbstractStorageUsageRecord.OperationType; import org.gcube.accounting.datamodel.basetypes.TestUsageRecord; import org.gcube.accounting.exception.InvalidValueException; import org.gcube.common.scope.api.ScopeProvider; import org.junit.Assert; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/ * */ public class StorageUsageRecordTest { - + + private static Logger logger = LoggerFactory.getLogger(StorageUsageRecordTest.class); + public static Set getExpectedRequiredFields(){ Set expectedRequiredFields = new HashSet(); expectedRequiredFields.add(BasicUsageRecordUtility.ID); @@ -71,4 +76,15 @@ public class StorageUsageRecordTest { storageUsageRecord.validate(); } + + @Test + public void signBasedOnOperation() throws InvalidValueException { + ScopeProvider.instance.set(TestUsageRecord.TEST_SCOPE); + StorageUsageRecord storageUsageRecord = TestUsageRecord.createTestStorageUsageRecordAutomaticScope(); + logger.debug("{}", storageUsageRecord.toString()); + storageUsageRecord.setOperationType(OperationType.DELETE); + storageUsageRecord.validate(); + logger.debug("{}", storageUsageRecord.toString()); + Assert.assertTrue(storageUsageRecord.getDataVolume()<0); + } }