mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Quota tariff order (#8347)
This commit is contained in:
parent
a87778be9a
commit
b9c7275c25
@ -150,3 +150,7 @@ SET
|
||||
WHERE
|
||||
name IN ("quota.usage.smtp.useStartTLS", "quota.usage.smtp.useAuth", "alert.smtp.useAuth", "project.smtp.useAuth")
|
||||
AND value NOT IN ("true", "y", "t", "1", "on", "yes");
|
||||
|
||||
|
||||
-- Quota inject tariff result into subsequent ones
|
||||
CALL `cloud_usage`.`IDEMPOTENT_ADD_COLUMN`('cloud_usage.quota_tariff', 'position', 'bigint(20) NOT NULL DEFAULT 1 COMMENT "Position in the execution sequence for tariffs of the same type"');
|
||||
|
||||
@ -20,6 +20,7 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
@ -36,6 +37,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariables;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.Tariff;
|
||||
import org.apache.cloudstack.quota.constant.QuotaConfig;
|
||||
import org.apache.cloudstack.quota.constant.QuotaTypes;
|
||||
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
|
||||
@ -371,9 +373,22 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
|
||||
PresetVariables presetVariables = getPresetVariables(hasAnyQuotaTariffWithActivationRule, usageRecord);
|
||||
BigDecimal aggregatedQuotaTariffsValue = BigDecimal.ZERO;
|
||||
|
||||
quotaTariffs.sort(Comparator.comparing(QuotaTariffVO::getPosition));
|
||||
|
||||
List<Tariff> lastTariffs = new ArrayList<>();
|
||||
|
||||
|
||||
for (QuotaTariffVO quotaTariff : quotaTariffs) {
|
||||
if (isQuotaTariffInPeriodToBeApplied(usageRecord, quotaTariff, accountToString)) {
|
||||
aggregatedQuotaTariffsValue = aggregatedQuotaTariffsValue.add(getQuotaTariffValueToBeApplied(quotaTariff, jsInterpreter, presetVariables));
|
||||
|
||||
BigDecimal tariffValue = getQuotaTariffValueToBeApplied(quotaTariff, jsInterpreter, presetVariables, lastTariffs);
|
||||
|
||||
aggregatedQuotaTariffsValue = aggregatedQuotaTariffsValue.add(tariffValue);
|
||||
|
||||
Tariff tariffPresetVariable = new Tariff();
|
||||
tariffPresetVariable.setId(quotaTariff.getUuid());
|
||||
tariffPresetVariable.setValue(tariffValue);
|
||||
lastTariffs.add(tariffPresetVariable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,7 +416,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
|
||||
* <li>If the activation rule result in something else, returns {@link BigDecimal#ZERO}.</li>
|
||||
* </ul>
|
||||
*/
|
||||
protected BigDecimal getQuotaTariffValueToBeApplied(QuotaTariffVO quotaTariff, JsInterpreter jsInterpreter, PresetVariables presetVariables) {
|
||||
protected BigDecimal getQuotaTariffValueToBeApplied(QuotaTariffVO quotaTariff, JsInterpreter jsInterpreter, PresetVariables presetVariables, List<Tariff> lastAppliedTariffsList) {
|
||||
String activationRule = quotaTariff.getActivationRule();
|
||||
BigDecimal quotaTariffValue = quotaTariff.getCurrencyValue();
|
||||
String quotaTariffToString = quotaTariff.toString(usageAggregationTimeZone);
|
||||
@ -413,6 +428,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
|
||||
}
|
||||
|
||||
injectPresetVariablesIntoJsInterpreter(jsInterpreter, presetVariables);
|
||||
jsInterpreter.injectVariable("lastTariffs", lastAppliedTariffsList.toString());
|
||||
|
||||
String scriptResult = jsInterpreter.executeScript(activationRule).toString();
|
||||
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.quota.activationrule.presetvariables;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class Tariff extends GenericPresetVariable {
|
||||
private BigDecimal value;
|
||||
|
||||
public BigDecimal getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(BigDecimal value) {
|
||||
this.value = value;
|
||||
fieldNamesToIncludeInToString.add("value");
|
||||
}
|
||||
}
|
||||
@ -93,6 +93,10 @@ public class QuotaTariffVO implements QuotaTariff {
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
private Date endDate;
|
||||
|
||||
@Column(name = "position")
|
||||
protected Integer position;
|
||||
|
||||
|
||||
public QuotaTariffVO() {
|
||||
}
|
||||
|
||||
@ -120,6 +124,7 @@ public class QuotaTariffVO implements QuotaTariff {
|
||||
this.setDescription(that.getDescription());
|
||||
this.setActivationRule(that.getActivationRule());
|
||||
this.setEndDate(that.getEndDate());
|
||||
this.setPosition(that.getPosition());
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
@ -263,6 +268,15 @@ public class QuotaTariffVO implements QuotaTariff {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "uuid", "name", "usageName");
|
||||
|
||||
@ -29,6 +29,7 @@ import org.apache.cloudstack.quota.activationrule.presetvariables.Domain;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariables;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.Tariff;
|
||||
import org.apache.cloudstack.quota.activationrule.presetvariables.Value;
|
||||
import org.apache.cloudstack.quota.constant.QuotaTypes;
|
||||
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
|
||||
@ -395,7 +396,7 @@ public class QuotaManagerImplTest {
|
||||
Mockito.doReturn(null).when(quotaTariffVoMock).getActivationRule();
|
||||
Mockito.doReturn(BigDecimal.ONE).when(quotaTariffVoMock).getCurrencyValue();
|
||||
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null);
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null, null);
|
||||
|
||||
Assert.assertEquals(BigDecimal.ONE, result);
|
||||
}
|
||||
@ -405,7 +406,7 @@ public class QuotaManagerImplTest {
|
||||
Mockito.doReturn("").when(quotaTariffVoMock).getActivationRule();
|
||||
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();
|
||||
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null);
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null, null);
|
||||
|
||||
Assert.assertEquals(BigDecimal.TEN, result);
|
||||
}
|
||||
@ -413,13 +414,15 @@ public class QuotaManagerImplTest {
|
||||
@Test
|
||||
public void getQuotaTariffValueToBeAppliedTestScriptResultIsNumberReturnIt() {
|
||||
BigDecimal expected = new BigDecimal(50.1);
|
||||
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);
|
||||
|
||||
|
||||
Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
|
||||
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();
|
||||
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
|
||||
Mockito.doReturn(expected).when(jsInterpreterMock).executeScript(Mockito.anyString());
|
||||
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);
|
||||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
@ -427,37 +430,42 @@ public class QuotaManagerImplTest {
|
||||
@Test
|
||||
public void getQuotaTariffValueToBeAppliedTestScriptResultIsTrueReturnTariffValue() {
|
||||
BigDecimal expected = new BigDecimal(236.84);
|
||||
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);
|
||||
|
||||
Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
|
||||
Mockito.doReturn(expected).when(quotaTariffVoMock).getCurrencyValue();
|
||||
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
|
||||
Mockito.doReturn(true).when(jsInterpreterMock).executeScript(Mockito.anyString());
|
||||
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);
|
||||
|
||||
Assert.assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getQuotaTariffValueToBeAppliedTestScriptResultIsFalseReturnZero() {
|
||||
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);
|
||||
|
||||
Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
|
||||
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();
|
||||
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
|
||||
Mockito.doReturn(false).when(jsInterpreterMock).executeScript(Mockito.anyString());
|
||||
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);
|
||||
|
||||
Assert.assertEquals(BigDecimal.ZERO, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getQuotaTariffValueToBeAppliedTestScriptResultIsNotBooleanNorNumericReturnZero() {
|
||||
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);
|
||||
|
||||
Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
|
||||
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();
|
||||
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
|
||||
Mockito.doReturn("test").when(jsInterpreterMock).executeScript(Mockito.anyString());
|
||||
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
|
||||
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);
|
||||
|
||||
Assert.assertEquals(BigDecimal.ZERO, result);
|
||||
}
|
||||
@ -477,10 +485,7 @@ public class QuotaManagerImplTest {
|
||||
|
||||
@Test
|
||||
public void aggregateQuotaTariffsValuesTestTariffsWereNotInPeriodToBeAppliedReturnZero() {
|
||||
List<QuotaTariffVO> tariffs = new ArrayList<>();
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
List<QuotaTariffVO> tariffs = createTariffList();
|
||||
|
||||
Mockito.doReturn(false).when(quotaManagerImplSpy).isQuotaTariffInPeriodToBeApplied(Mockito.any(), Mockito.any(), Mockito.anyString());
|
||||
BigDecimal result = quotaManagerImplSpy.aggregateQuotaTariffsValues(usageVoMock, tariffs, false, jsInterpreterMock, "");
|
||||
@ -497,13 +502,10 @@ public class QuotaManagerImplTest {
|
||||
|
||||
@Test
|
||||
public void aggregateQuotaTariffsValuesTestTariffsAreInPeriodToBeAppliedReturnAggregation() {
|
||||
List<QuotaTariffVO> tariffs = new ArrayList<>();
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
List<QuotaTariffVO> tariffs = createTariffList();
|
||||
|
||||
Mockito.doReturn(true, false, true).when(quotaManagerImplSpy).isQuotaTariffInPeriodToBeApplied(Mockito.any(), Mockito.any(), Mockito.anyString());
|
||||
Mockito.doReturn(BigDecimal.TEN).when(quotaManagerImplSpy).getQuotaTariffValueToBeApplied(Mockito.any(), Mockito.any(), Mockito.any());
|
||||
Mockito.doReturn(BigDecimal.TEN).when(quotaManagerImplSpy).getQuotaTariffValueToBeApplied(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
|
||||
BigDecimal result = quotaManagerImplSpy.aggregateQuotaTariffsValues(usageVoMock, tariffs, false, jsInterpreterMock, "");
|
||||
|
||||
Assert.assertEquals(BigDecimal.TEN.multiply(new BigDecimal(2)), result);
|
||||
@ -528,4 +530,25 @@ public class QuotaManagerImplTest {
|
||||
Assert.assertEquals(quotaUsageVoMock1, result.get(0));
|
||||
Assert.assertEquals(quotaUsageVoMock2, result.get(1));
|
||||
}
|
||||
|
||||
private static List<QuotaTariffVO> createTariffList() {
|
||||
List<QuotaTariffVO> tariffs = new ArrayList<>();
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
tariffs.add(new QuotaTariffVO());
|
||||
tariffs.forEach(quotaTariffVO -> quotaTariffVO.setPosition(1));
|
||||
return tariffs;
|
||||
}
|
||||
|
||||
private static List<Tariff> createLastAppliedTariffsPresetVariableList(int numberOfTariffs) {
|
||||
List<Tariff> lastTariffs = new ArrayList<>();
|
||||
for (int i = 0; i < numberOfTariffs; i++) {
|
||||
Tariff tariff = new Tariff();
|
||||
tariff.setId(String.valueOf(i));
|
||||
tariff.setValue(BigDecimal.valueOf(i));
|
||||
lastTariffs.add(tariff);
|
||||
}
|
||||
return lastTariffs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -68,6 +68,9 @@ public class QuotaTariffCreateCmd extends BaseCmd {
|
||||
ApiConstants.PARAMETER_DESCRIPTION_END_DATE_POSSIBLE_FORMATS)
|
||||
private Date endDate;
|
||||
|
||||
@Parameter(name = ApiConstants.POSITION, type = CommandType.INTEGER, description = "Position in the execution sequence for tariffs of the same type", since = "4.20.0.0")
|
||||
private Integer position;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
CallContext.current().setEventDetails(String.format("Tariff: %s, description: %s, value: %s", getName(), getDescription(), getValue()));
|
||||
@ -139,4 +142,13 @@ public class QuotaTariffCreateCmd extends BaseCmd {
|
||||
public ApiCommandResourceType getApiResourceType() {
|
||||
return ApiCommandResourceType.QuotaTariff;
|
||||
}
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -69,6 +69,9 @@ public class QuotaTariffUpdateCmd extends BaseCmd {
|
||||
"value will be applied. Inform empty to remove the activation rule.", length = 65535, since = "4.18.0.0")
|
||||
private String activationRule;
|
||||
|
||||
@Parameter(name = ApiConstants.POSITION, type = CommandType.INTEGER, description = "Position in the execution sequence for tariffs of the same type", since = "4.20.0.0")
|
||||
private Integer position;
|
||||
|
||||
public Integer getUsageType() {
|
||||
return usageType;
|
||||
}
|
||||
@ -130,4 +133,13 @@ public class QuotaTariffUpdateCmd extends BaseCmd {
|
||||
public ApiCommandResourceType getApiResourceType() {
|
||||
return ApiCommandResourceType.QuotaTariff;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -80,6 +80,7 @@ import org.apache.cloudstack.quota.vo.QuotaUsageVO;
|
||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -151,6 +152,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
response.setDescription(tariff.getDescription());
|
||||
response.setId(tariff.getUuid());
|
||||
response.setRemoved(tariff.getRemoved());
|
||||
response.setPosition(tariff.getPosition());
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -414,6 +416,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
String description = cmd.getDescription();
|
||||
String activationRule = cmd.getActivationRule();
|
||||
Date now = new Date();
|
||||
Integer position = cmd.getPosition();
|
||||
|
||||
warnQuotaTariffUpdateDeprecatedFields(cmd);
|
||||
|
||||
@ -428,7 +431,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
currentQuotaTariff.setRemoved(now);
|
||||
|
||||
QuotaTariffVO newQuotaTariff = persistNewQuotaTariff(currentQuotaTariff, name, 0, currentQuotaTariffStartDate, cmd.getEntityOwnerId(), endDate, value, description,
|
||||
activationRule);
|
||||
activationRule, position);
|
||||
_quotaTariffDao.updateQuotaTariff(currentQuotaTariff);
|
||||
|
||||
CallContext.current().setEventResourceId(newQuotaTariff.getId());
|
||||
@ -449,7 +452,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
}
|
||||
|
||||
protected QuotaTariffVO persistNewQuotaTariff(QuotaTariffVO currentQuotaTariff, String name, int usageType, Date startDate, Long entityOwnerId, Date endDate, Double value,
|
||||
String description, String activationRule) {
|
||||
String description, String activationRule, Integer position) {
|
||||
|
||||
QuotaTariffVO newQuotaTariff = getNewQuotaTariffObject(currentQuotaTariff, name, usageType);
|
||||
|
||||
@ -461,6 +464,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
validateValueOnCreatingNewQuotaTariff(newQuotaTariff, value);
|
||||
validateStringsOnCreatingNewQuotaTariff(newQuotaTariff::setDescription, description);
|
||||
validateStringsOnCreatingNewQuotaTariff(newQuotaTariff::setActivationRule, activationRule);
|
||||
validatePositionOnCreatingNewQuotaTariff(newQuotaTariff, position);
|
||||
|
||||
_quotaTariffDao.addQuotaTariff(newQuotaTariff);
|
||||
return newQuotaTariff;
|
||||
@ -481,6 +485,13 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
return newQuotaTariff;
|
||||
}
|
||||
|
||||
protected void validatePositionOnCreatingNewQuotaTariff(QuotaTariffVO newQuotaTariff, Integer position) {
|
||||
if (position != null) {
|
||||
newQuotaTariff.setPosition(position);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void validateStringsOnCreatingNewQuotaTariff(Consumer<String> method, String value){
|
||||
if (value != null) {
|
||||
method.accept(value.isBlank() ? null : value);
|
||||
@ -663,6 +674,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
Double value = cmd.getValue();
|
||||
String description = cmd.getDescription();
|
||||
String activationRule = cmd.getActivationRule();
|
||||
Integer position = ObjectUtils.defaultIfNull(cmd.getPosition(), 1);
|
||||
|
||||
QuotaTariffVO currentQuotaTariff = _quotaTariffDao.findByName(name);
|
||||
|
||||
@ -675,7 +687,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
|
||||
"Please, inform a date in the future or do not pass the parameter to use the current date and time.", startDate));
|
||||
}
|
||||
|
||||
QuotaTariffVO newQuotaTariff = persistNewQuotaTariff(null, name, usageType, startDate, cmd.getEntityOwnerId(), endDate, value, description, activationRule);
|
||||
QuotaTariffVO newQuotaTariff = persistNewQuotaTariff(null, name, usageType, startDate, cmd.getEntityOwnerId(), endDate, value, description, activationRule, position);
|
||||
|
||||
CallContext.current().setEventResourceId(newQuotaTariff.getId());
|
||||
|
||||
|
||||
@ -83,6 +83,11 @@ public class QuotaTariffResponse extends BaseResponse {
|
||||
@Param(description = "when the quota tariff was removed")
|
||||
private Date removed;
|
||||
|
||||
@SerializedName("position")
|
||||
@Param(description = "position in the execution sequence for tariffs of the same type")
|
||||
private Integer position;
|
||||
|
||||
|
||||
public QuotaTariffResponse() {
|
||||
super();
|
||||
this.setObjectName("quotatariff");
|
||||
@ -172,4 +177,12 @@ public class QuotaTariffResponse extends BaseResponse {
|
||||
this.removed = removed;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -372,8 +372,10 @@ public class QuotaResponseBuilderImplTest extends TestCase {
|
||||
Mockito.doNothing().when(quotaResponseBuilderSpy).validateValueOnCreatingNewQuotaTariff(Mockito.any(QuotaTariffVO.class), Mockito.anyDouble());
|
||||
Mockito.doNothing().when(quotaResponseBuilderSpy).validateStringsOnCreatingNewQuotaTariff(Mockito.any(Consumer.class), Mockito.anyString());
|
||||
Mockito.doReturn(quotaTariffVoMock).when(quotaTariffDaoMock).addQuotaTariff(Mockito.any(QuotaTariffVO.class));
|
||||
Mockito.doNothing().when(quotaResponseBuilderSpy).validatePositionOnCreatingNewQuotaTariff(Mockito.any(QuotaTariffVO.class), Mockito.anyInt());
|
||||
|
||||
quotaResponseBuilderSpy.persistNewQuotaTariff(quotaTariffVoMock, "", 1, date, 1l, date, 1.0, "", "");
|
||||
|
||||
quotaResponseBuilderSpy.persistNewQuotaTariff(quotaTariffVoMock, "", 1, date, 1l, date, 1.0, "", "", 2);
|
||||
|
||||
Mockito.verify(quotaTariffDaoMock).addQuotaTariff(Mockito.any(QuotaTariffVO.class));
|
||||
}
|
||||
@ -553,4 +555,18 @@ public class QuotaResponseBuilderImplTest extends TestCase {
|
||||
assertEquals(2, result.getEmailTemplateId());
|
||||
assertFalse(result.isEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatePositionOnCreatingNewQuotaTariffTestNullValueDoNothing() {
|
||||
quotaResponseBuilderSpy.validatePositionOnCreatingNewQuotaTariff(quotaTariffVoMock, null);
|
||||
Mockito.verify(quotaTariffVoMock, Mockito.never()).setPosition(Mockito.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatePositionOnCreatingNewQuotaTariffTestAnyValueIsSet() {
|
||||
Integer position = 1;
|
||||
quotaResponseBuilderSpy.validatePositionOnCreatingNewQuotaTariff(quotaTariffVoMock, position);
|
||||
Mockito.verify(quotaTariffVoMock).setPosition(position);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
175
test/integration/plugins/test_quota_tariff_order.py
Normal file
175
test/integration/plugins/test_quota_tariff_order.py
Normal file
@ -0,0 +1,175 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
""" Test cases for checking quota API
|
||||
"""
|
||||
|
||||
# Import Local Modules
|
||||
import tools.marvin.marvin
|
||||
from tools.marvin.marvin.cloudstackTestCase import *
|
||||
from tools.marvin.marvin.cloudstackAPI import *
|
||||
from tools.marvin.marvin.lib.utils import *
|
||||
from tools.marvin.marvin.lib.base import *
|
||||
from tools.marvin.marvin.lib.common import *
|
||||
from nose.plugins.attrib import attr
|
||||
|
||||
# Import System modules
|
||||
import time
|
||||
|
||||
|
||||
class TestQuotaTariffOrder(cloudstackTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
testClient = super(TestQuotaTariffOrder, cls).getClsTestClient()
|
||||
cls.api_client = testClient.getApiClient()
|
||||
cls.services = testClient.getParsedTestDataConfig()
|
||||
|
||||
# Get Zone, Domain and templates
|
||||
cls.domain = get_domain(cls.api_client)
|
||||
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
|
||||
|
||||
cls._cleanup = []
|
||||
# Create Account
|
||||
cls.account = Account.create(
|
||||
cls.api_client,
|
||||
cls.services["account"],
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls._cleanup.append(cls.account)
|
||||
|
||||
cls.services["account"] = cls.account.name
|
||||
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestQuotaTariffOrder, cls).tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.dbclient = self.testClient.getDbConnection()
|
||||
self.cleanup = []
|
||||
self.tariffs = []
|
||||
return
|
||||
|
||||
def tearDown(self):
|
||||
self.delete_tariffs()
|
||||
super(TestQuotaTariffOrder, self).tearDown()
|
||||
|
||||
def delete_tariffs(self):
|
||||
for tariff in self.tariffs:
|
||||
cmd = quotaTariffDelete.quotaTariffDeleteCmd()
|
||||
cmd.id = tariff.uuid
|
||||
self.api_client.quotaTariffDelete(cmd)
|
||||
|
||||
@attr(
|
||||
tags=[
|
||||
"advanced",
|
||||
"smoke"],
|
||||
required_hardware="false")
|
||||
def test_01_quota_tariff_order(self):
|
||||
"""Test Quota Tariff Order
|
||||
"""
|
||||
|
||||
cmd = quotaTariffCreate.quotaTariffCreateCmd()
|
||||
cmd.name = 'tf1'
|
||||
cmd.value = '1'
|
||||
cmd.activationrule = '10'
|
||||
cmd.usagetype = '22'
|
||||
cmd.position = '2'
|
||||
self.tariffs.append(self.api_client.quotaTariffCreate(cmd))
|
||||
|
||||
cmd = quotaTariffCreate.quotaTariffCreateCmd()
|
||||
cmd.name = 'tf2'
|
||||
cmd.value = '1'
|
||||
cmd.activationrule = 'lastTariffs[lastTariffs.length -1].value + 7'
|
||||
cmd.usagetype = '22'
|
||||
cmd.position = '3'
|
||||
self.tariffs.append(self.api_client.quotaTariffCreate(cmd))
|
||||
|
||||
cmd = quotaTariffCreate.quotaTariffCreateCmd()
|
||||
cmd.name = 'tf3'
|
||||
cmd.value = '1'
|
||||
cmd.activationrule = 'lastTariffs[lastTariffs.length -2].value + lastTariffs[lastTariffs.length -1].value'
|
||||
cmd.usagetype = '22'
|
||||
cmd.position = '4'
|
||||
self.tariffs.append(self.api_client.quotaTariffCreate(cmd))
|
||||
|
||||
cmd = quotaCredits.quotaCreditsCmd()
|
||||
cmd.account = self.account.name
|
||||
cmd.domainid = self.domain.id
|
||||
cmd.value = 54
|
||||
self.api_client.quotaCredits(cmd)
|
||||
|
||||
# Fetch account ID from account_uuid
|
||||
self.debug("select id from account where uuid = '%s';"
|
||||
% self.account.id)
|
||||
|
||||
qresultset = self.dbclient.execute(
|
||||
"select id from account where uuid = '%s';"
|
||||
% self.account.id
|
||||
)
|
||||
|
||||
account_id = qresultset[0][0]
|
||||
|
||||
self.debug("SELECT id from `domain` d WHERE uuid = '%s';"
|
||||
% self.domain.id)
|
||||
|
||||
qresultset = self.dbclient.execute(
|
||||
"SELECT id from `domain` d WHERE uuid = '%s';"
|
||||
% self.domain.id
|
||||
)
|
||||
|
||||
domain_id = qresultset[0][0]
|
||||
|
||||
self.debug("SELECT id from data_center dc where dc.uuid = '%s';"
|
||||
% self.zone.id)
|
||||
|
||||
qresultset = self.dbclient.execute(
|
||||
"SELECT id from data_center dc where dc.uuid = '%s';"
|
||||
% self.zone.id
|
||||
)
|
||||
|
||||
zone_id = qresultset[0][0]
|
||||
|
||||
start = datetime.datetime.now() + datetime.timedelta(seconds=1)
|
||||
end = datetime.datetime.now() + datetime.timedelta(hours=1)
|
||||
|
||||
query = "INSERT INTO cloud_usage.cloud_usage (zone_id,account_id,domain_id,description,usage_display,"
|
||||
"usage_type,raw_usage,vm_instance_id,vm_name,offering_id,template_id,usage_id,`type`,`size`,"
|
||||
"network_id,start_date,end_date,virtual_size,cpu_speed,cpu_cores,memory,quota_calculated,"
|
||||
"is_hidden,state) VALUES ('{}','{}','{}','Test','1 Hrs',22,1,NULL,NULL,NULL,NULL,NULL,"
|
||||
"'VirtualMachine',NULL,NULL,'{}','{}',NULL,NULL,NULL,NULL,0,0,NULL);".format(zone_id, account_id, domain_id, start, end)
|
||||
|
||||
self.debug(query)
|
||||
|
||||
self.dbclient.execute(
|
||||
query)
|
||||
|
||||
cmd = quotaUpdate.quotaUpdateCmd()
|
||||
self.api_client.quotaUpdate(cmd)
|
||||
|
||||
cmd = quotaBalance.quotaBalanceCmd()
|
||||
cmd.domainid = self.account.domainid
|
||||
cmd.account = self.account.name
|
||||
response = self.apiclient.quotaBalance(cmd)
|
||||
|
||||
self.debug(f"Quota Balance: {response.balance}")
|
||||
|
||||
self.assertEqual(response.balance.startquota, 0, f"startQuota is supposed to be 0 but was {response.balance.startquota}")
|
||||
|
||||
return
|
||||
Loading…
x
Reference in New Issue
Block a user