From a03c4b55167a68e147bcda5b9be1425e21fcf64e Mon Sep 17 00:00:00 2001 From: Andrey Tsibin Date: Fri, 14 Apr 2023 13:59:44 +0300 Subject: [PATCH 1/6] Introduce instance start date in database --- .../pipeline/dao/pipeline/PipelineRunDao.java | 8 ++- api/src/main/resources/dao/filter-dao.xml | 3 +- .../main/resources/dao/pipeline-run-dao.xml | 69 +++++++++++++------ ...00__issue_3201_run_instance_start_date.sql | 2 + .../dao/pipeline/PipelineRunDaoTest.java | 52 ++++++++++++++ .../com/epam/pipeline/util/TestUtils.java | 1 + .../pipeline/entity/pipeline/PipelineRun.java | 12 ++++ .../pipeline/entity/pipeline/RunInstance.java | 3 + .../pipeline/entity/pipeline/PipelineRun.java | 11 +++ .../pipeline/entity/pipeline/RunInstance.java | 2 + 10 files changed, 141 insertions(+), 22 deletions(-) create mode 100644 api/src/main/resources/db/migration/v2023.04.13_14.00__issue_3201_run_instance_start_date.sql diff --git a/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java b/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java index 1e76f0023c..0f3c73e34f 100644 --- a/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java +++ b/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java @@ -835,7 +835,8 @@ public enum PipelineRunParameters { SENSITIVE, KUBE_SERVICE_ENABLED, CLUSTER_PRICE, - NODE_POOL_ID; + NODE_POOL_ID, + NODE_START_DATE; public static final RunAccessType DEFAULT_ACCESS_TYPE = RunAccessType.ENDPOINT; @@ -903,6 +904,7 @@ private static void addInstanceFields(PipelineRun run, MapSqlParameterSource par instance.map(RunInstance::getCloudProvider).map(CloudProvider::name).orElse(null)); params.addValue(NODE_PLATFORM.name(), instance.map(RunInstance::getNodePlatform).orElse(null)); params.addValue(NODE_POOL_ID.name(), instance.map(RunInstance::getPoolId).orElse(null)); + params.addValue(NODE_START_DATE.name(), instance.map(RunInstance::getStartDate).orElse(null)); } static ResultSetExtractor> getRunGroupExtractor() { @@ -985,6 +987,10 @@ public static PipelineRun parsePipelineRun(ResultSet rs) throws SQLException { instance.setCloudProvider(CloudProvider.valueOf(rs.getString(NODE_CLOUD_PROVIDER.name()))); instance.setNodePlatform(rs.getString(NODE_PLATFORM.name())); instance.setPoolId(rs.getLong(NODE_POOL_ID.name())); + Timestamp instanceStart = rs.getTimestamp(NODE_START_DATE.name()); + if (!rs.wasNull()) { + instance.setStartDate(new Date(instanceStart.getTime())); + } boolean spot = rs.getBoolean(IS_SPOT.name()); if (!rs.wasNull()) { diff --git a/api/src/main/resources/dao/filter-dao.xml b/api/src/main/resources/dao/filter-dao.xml index 7371c2a6e3..7f03792287 100644 --- a/api/src/main/resources/dao/filter-dao.xml +++ b/api/src/main/resources/dao/filter-dao.xml @@ -74,7 +74,8 @@ r.kube_service_enabled, r.pipeline_name, r.cluster_price, - r.node_pool_id + r.node_pool_id, + r.node_start_date FROM pipeline.pipeline_run r WHERE @WHERE@ diff --git a/api/src/main/resources/dao/pipeline-run-dao.xml b/api/src/main/resources/dao/pipeline-run-dao.xml index d9d0ea7926..91a7d0e1f3 100644 --- a/api/src/main/resources/dao/pipeline-run-dao.xml +++ b/api/src/main/resources/dao/pipeline-run-dao.xml @@ -73,7 +73,8 @@ node_cloud_provider, tags, sensitive, - pipeline_name) + pipeline_name, + node_start_date) VALUES ( :RUN_ID, :PIPELINE_ID, @@ -124,7 +125,8 @@ :NODE_CLOUD_PROVIDER, to_jsonb(:TAGS::jsonb), :SENSITIVE, - :PIPELINE_NAME) + :PIPELINE_NAME, + :NODE_START_DATE) ]]> @@ -184,6 +186,7 @@ r.cluster_price, r.pipeline_name, r.node_pool_id, + r.node_start_date, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -277,7 +280,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -342,7 +346,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -407,7 +412,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -452,7 +458,8 @@ node_name =:NODE_NAME, is_spot =:IS_SPOT, node_real_disk =:NODE_REAL_DISK, - node_pool_id = :NODE_POOL_ID + node_pool_id = :NODE_POOL_ID, + node_start_date = :NODE_START_DATE WHERE run_id = :RUN_ID ]]> @@ -509,7 +516,8 @@ tags = to_jsonb(:TAGS::jsonb), sensitive = :SENSITIVE, kube_service_enabled = :KUBE_SERVICE_ENABLED, - pipeline_name = :PIPELINE_NAME + pipeline_name = :PIPELINE_NAME, + node_start_date = :NODE_START_DATE WHERE run_id = :RUN_ID ]]> @@ -615,7 +623,8 @@ FALSE as queued, r.pipeline_name, r.cluster_price, - r.node_pool_id + r.node_pool_id, + r.node_start_date FROM pipeline.pipeline_run r WHERE @@ -681,7 +690,8 @@ FALSE as queued, r.pipeline_name, r.cluster_price, - r.node_pool_id + r.node_pool_id, + r.node_start_date FROM pipeline.pipeline_run r WHERE @@ -746,6 +756,7 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, + r.node_start_date, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_service_url su @@ -811,6 +822,7 @@ active_run.pipeline_name, active_run.cluster_price, active_run.node_pool_id, + active_run.node_start_date, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_service_url su @@ -887,6 +899,7 @@ r.sensitive, r.pipeline_name, r.node_pool_id, + r.node_start_date, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_service_url su @@ -949,6 +962,7 @@ active_run.sensitive, active_run.pipeline_name, active_run.node_pool_id, + active_run.node_start_date, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_service_url su @@ -1024,7 +1038,8 @@ r.kube_service_enabled, r.pipeline_name, r.cluster_price, - r.node_pool_id + r.node_pool_id, + r.node_start_date FROM pipeline.pipeline_run r WHERE @@ -1087,7 +1102,8 @@ r.kube_service_enabled, r.pipeline_name, r.cluster_price, - r.node_pool_id + r.node_pool_id, + r.node_start_date FROM pipeline.pipeline_run r WHERE @@ -1151,6 +1167,7 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, + r.node_start_date, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -1240,6 +1257,7 @@ runs.kube_service_enabled, runs.cluster_price, runs.node_pool_id, + runs.node_start_date, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -1318,7 +1336,8 @@ p.kube_service_enabled, p.pipeline_name, p.cluster_price, - p.node_pool_id + p.node_pool_id, + p.node_start_date FROM (SELECT * FROM pipeline.pipeline_run r WHERE parent_id ISNULL @WHERE@ @@ -1377,7 +1396,8 @@ c.kube_service_enabled, c.pipeline_name, c.cluster_price, - c.node_pool_id + c.node_pool_id, + c.node_start_date FROM pipeline.pipeline_run c INNER JOIN runs ON runs.run_id = c.parent_id @@ -1434,6 +1454,7 @@ runs.kube_service_enabled, runs.cluster_price, runs.node_pool_id, + runs.node_start_date CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -1510,6 +1531,7 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, + r.node_start_date, ( SELECT count(*) FROM pipeline.pipeline_run cr @@ -1674,7 +1696,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run r INNER JOIN (SELECT DISTINCT ON (run_id) run_id, status @@ -1753,7 +1776,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -1818,7 +1842,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -1883,7 +1908,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -1948,7 +1974,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -2023,7 +2050,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE @@ -2088,7 +2116,8 @@ kube_service_enabled, pipeline_name, cluster_price, - node_pool_id + node_pool_id, + node_start_date FROM pipeline.pipeline_run WHERE diff --git a/api/src/main/resources/db/migration/v2023.04.13_14.00__issue_3201_run_instance_start_date.sql b/api/src/main/resources/db/migration/v2023.04.13_14.00__issue_3201_run_instance_start_date.sql new file mode 100644 index 0000000000..b76ca1c35f --- /dev/null +++ b/api/src/main/resources/db/migration/v2023.04.13_14.00__issue_3201_run_instance_start_date.sql @@ -0,0 +1,2 @@ +ALTER TABLE pipeline.pipeline_run ADD COLUMN node_start_date TIMESTAMP WITH TIME ZONE; +UPDATE pipeline.pipeline_run SET node_start_date = start_date; diff --git a/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java b/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java index de5549829e..9bac83775e 100644 --- a/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java +++ b/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java @@ -920,6 +920,56 @@ public void shouldCreatePipelineRunWithPipelineName() { assertThat(loadedRun.getPipelineName(), is(TEST_PIPELINE_NAME)); } + @Test + public void shouldCreatePipelineRunWithStartedDate() { + final PipelineRun run = buildPipelineRun(testPipeline.getId()); + pipelineRunDao.createPipelineRun(run); + + final PipelineRun loadedRun = pipelineRunDao.loadPipelineRun(run.getId()); + assertNotNull(loadedRun.getStartDate()); + } + + @Test + public void shouldCreatePipelineRunWithEndedDate() { + final PipelineRun run = buildPipelineRun(testPipeline.getId()); + pipelineRunDao.createPipelineRun(run); + + final PipelineRun loadedRun = pipelineRunDao.loadPipelineRun(run.getId()); + assertNotNull(loadedRun.getEndDate()); + } + + @Test + public void shouldCreatePipelineRunWithInstanceStartedDate() { + final PipelineRun run = buildPipelineRun(testPipeline.getId()); + pipelineRunDao.createPipelineRun(run); + + final PipelineRun loadedRun = pipelineRunDao.loadPipelineRun(run.getId()); + assertNotNull(loadedRun.getInstance().getStartDate()); + } + + @Test + public void shouldCreatePipelineRunWithoutInstanceStartedDate() { + final PipelineRun run = buildPipelineRun(testPipeline.getId()); + run.getInstance().setStartDate(null); + pipelineRunDao.createPipelineRun(run); + + final PipelineRun loadedRun = pipelineRunDao.loadPipelineRun(run.getId()); + assertNull(loadedRun.getInstance().getStartDate()); + } + + @Test + public void shouldUpdatePipelineRunInstanceWithInstanceStartedDate() { + final PipelineRun run = buildPipelineRun(testPipeline.getId()); + run.getInstance().setStartDate(null); + pipelineRunDao.createPipelineRun(run); + + run.getInstance().setStartDate(run.getStartDate()); + pipelineRunDao.updateRunInstance(run); + + final PipelineRun loadedRun = pipelineRunDao.loadPipelineRun(run.getId()); + assertNotNull(loadedRun.getInstance().getStartDate()); + } + @Test public void shouldBatchUpdateRuns() { final PipelineRun run1 = buildPipelineRun(testPipeline.getId()); @@ -1105,6 +1155,7 @@ private void setRunInstance(final PipelineRun run) { runInstance.setCloudProvider(CloudProvider.AWS); runInstance.setCloudRegionId(cloudRegion.getId()); runInstance.setNodePlatform(TEST_PLATFORM); + runInstance.setStartDate(run.getStartDate()); run.setInstance(runInstance); } @@ -1183,6 +1234,7 @@ private PipelineRun createPipelineRun(Long pipelineId, String params, TaskStatus instance.setSpot(isSpot); instance.setNodeId("1"); instance.setNodePlatform(TEST_PLATFORM); + instance.setStartDate(run.getStartDate()); run.setInstance(instance); run.setEntitiesIds(Collections.singletonList(entitiesId)); run.setConfigurationId(configurationId); diff --git a/api/src/test/java/com/epam/pipeline/util/TestUtils.java b/api/src/test/java/com/epam/pipeline/util/TestUtils.java index 78360aec8d..4b6f621f61 100644 --- a/api/src/test/java/com/epam/pipeline/util/TestUtils.java +++ b/api/src/test/java/com/epam/pipeline/util/TestUtils.java @@ -158,6 +158,7 @@ public static PipelineRun createPipelineRun(Long pipelineId, String params, Task instance.setSpot(isSpot); instance.setNodeId("1"); instance.setNodePlatform(TEST_PLATFORM); + instance.setStartDate(new Date()); run.setInstance(instance); run.setEntitiesIds(Collections.singletonList(entitiesId)); run.setConfigurationId(configurationId); diff --git a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java index c0caa85496..5ade756f4c 100644 --- a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java +++ b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java @@ -24,6 +24,7 @@ import com.epam.pipeline.entity.pipeline.run.parameter.PipelineRunParameter; import com.epam.pipeline.entity.pipeline.run.parameter.RunSid; import com.epam.pipeline.entity.security.acl.AclClass; +import com.epam.pipeline.entity.utils.DateUtils; import com.fasterxml.jackson.annotation.JsonIgnore; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -33,6 +34,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; import lombok.AllArgsConstructor; @@ -187,4 +189,14 @@ public Map convertParamsToMap() { public String getTaskName() { return StringUtils.isEmpty(pipelineName) ? podId : pipelineName; } + + @JsonIgnore + public Date getInstanceStartDate() { + return Optional.ofNullable(instance).map(RunInstance::getStartDate).orElse(null); + } + + @JsonIgnore + public LocalDateTime getInstanceStartDateTime() { + return Optional.ofNullable(getInstanceStartDate()).map(DateUtils::convertDateToLocalDateTime).orElse(null); + } } diff --git a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java index 02d8c13851..5e27d5215d 100644 --- a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java +++ b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java @@ -18,6 +18,8 @@ import com.epam.pipeline.entity.region.CloudProvider; import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.util.Date; import java.util.Objects; import java.util.Set; @@ -58,6 +60,7 @@ public class RunInstance { */ private Set prePulledDockerImages; private Long poolId; + private Date startDate; @JsonIgnore public boolean isEmpty() { diff --git a/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java b/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java index 046ef0d595..0a04d347eb 100644 --- a/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java +++ b/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java @@ -24,6 +24,7 @@ import com.epam.pipeline.entity.pipeline.run.parameter.PipelineRunParameter; import com.epam.pipeline.entity.pipeline.run.parameter.RunSid; import com.epam.pipeline.entity.security.acl.AclClass; +import com.epam.pipeline.entity.utils.DateUtils; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; @@ -253,4 +254,14 @@ public void addTag(final String key, final String value) { public void removeTag(final String key) { tags.remove(key); } + + @JsonIgnore + public Date getInstanceStartDate() { + return Optional.ofNullable(instance).map(RunInstance::getStartDate).orElse(null); + } + + @JsonIgnore + public LocalDateTime getInstanceStartDateTime() { + return Optional.ofNullable(getInstanceStartDate()).map(DateUtils::convertDateToLocalDateTime).orElse(null); + } } diff --git a/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java b/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java index 15aa0d7ed5..b3a5c984ce 100644 --- a/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java +++ b/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java @@ -25,6 +25,7 @@ import lombok.ToString; import org.springframework.util.StringUtils; +import java.util.Date; import java.util.Objects; import java.util.Set; @@ -60,6 +61,7 @@ public class RunInstance { */ private Set prePulledDockerImages; private Long poolId; + private Date startDate; public RunInstance(final String nodeType, final Integer nodeDisk, From e0dd3aa4d6afc000aa11a3d7450b518f5d9ab329 Mon Sep 17 00:00:00 2001 From: Andrey Tsibin Date: Fri, 14 Apr 2023 16:43:14 +0300 Subject: [PATCH 2/6] Use instance start date in api --- .../manager/cluster/InstanceOfferManager.java | 6 ++--- .../pipeline/manager/cluster/PodMonitor.java | 3 ++- .../cluster/autoscale/AutoscaleManager.java | 4 ++- .../autoscale/AutoscalerServiceImpl.java | 2 +- .../cluster/autoscale/ReassignHandler.java | 2 ++ .../ClusterCostsMonitoringServiceCore.java | 16 ++---------- .../pipeline/mapper/PipelineRunMapper.java | 5 ++-- .../epam/pipeline/utils/RunDurationUtils.java | 25 +++++++++++++++++++ .../impl/mapper/StorageBillingMapperTest.java | 2 +- 9 files changed, 41 insertions(+), 24 deletions(-) create mode 100644 api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/InstanceOfferManager.java b/api/src/main/java/com/epam/pipeline/manager/cluster/InstanceOfferManager.java index 1959ef8257..bd16f42aec 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/InstanceOfferManager.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/InstanceOfferManager.java @@ -39,6 +39,7 @@ import com.epam.pipeline.manager.preference.PreferenceManager; import com.epam.pipeline.manager.preference.SystemPreferences; import com.epam.pipeline.manager.region.CloudRegionManager; +import com.epam.pipeline.utils.RunDurationUtils; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.apache.commons.collections4.ListUtils; @@ -143,7 +144,7 @@ public InstancePrice getInstanceEstimatedPrice(Long id, String version, String c long maximumDuration = -1; long totalDurations = 0; for (PipelineRun run : runs) { - long duration = run.getEndDate().getTime() - run.getStartDate().getTime(); + long duration = RunDurationUtils.getBillableDuration(run).toMillis(); if (minimumDuration == -1 || minimumDuration > duration) { minimumDuration = duration; } @@ -191,8 +192,7 @@ public PipelineRunPrice getPipelineRunEstimatedPrice(Long runId, Long regionId) price.setPricePerHour(pricePerHour); if (pipelineRun.getStatus().isFinal()) { - long duration = pipelineRun.getEndDate().getTime() - pipelineRun.getStartDate().getTime(); - price.setTotalPrice(duration / ONE_HOUR * pricePerHour); + price.setTotalPrice(RunDurationUtils.getBillableDuration(pipelineRun).toMillis() / ONE_HOUR * pricePerHour); } else { price.setTotalPrice(0); } diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/PodMonitor.java b/api/src/main/java/com/epam/pipeline/manager/cluster/PodMonitor.java index 7d2d761e45..23ba635986 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/PodMonitor.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/PodMonitor.java @@ -41,6 +41,7 @@ import com.epam.pipeline.manager.preference.PreferenceManager; import com.epam.pipeline.manager.preference.SystemPreferences; import com.epam.pipeline.manager.scheduling.AbstractSchedulingManager; +import com.epam.pipeline.utils.RunDurationUtils; import io.fabric8.kubernetes.api.model.ContainerStatus; import io.fabric8.kubernetes.api.model.Node; import io.fabric8.kubernetes.api.model.Pod; @@ -292,7 +293,7 @@ private long runningDurationOf(final PipelineRun run) { } private long overallDurationOf(final PipelineRun run) { - return Duration.between(run.getStartDate().toInstant(), DateUtils.now().toInstant()).abs().getSeconds(); + return RunDurationUtils.getOverallDuration(run).getSeconds(); } private List toSortedStatuses(final List statuses) { diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java index 17f65e3904..723bd90cdc 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java @@ -25,6 +25,7 @@ import com.epam.pipeline.entity.pipeline.run.parameter.PipelineRunParameter; import com.epam.pipeline.entity.pipeline.run.parameter.RuntimeParameter; import com.epam.pipeline.entity.pipeline.run.parameter.RuntimeParameterType; +import com.epam.pipeline.entity.utils.DateUtils; import com.epam.pipeline.exception.CmdExecutionException; import com.epam.pipeline.exception.git.GitClientException; import com.epam.pipeline.manager.cloud.CloudFacade; @@ -490,7 +491,8 @@ private void createNodeForRun(List> tasks, String runId, pipelineRunManager.updateRunInstance(longId, requiredInstance.getInstance()); RunInstance instance = cloudFacade .scaleUpNode(longId, requiredInstance.getInstance(), requiredInstance.getRuntimeParameters()); - //save instance ID and IP + instance.setStartDate(DateUtils.now()); + //save actual instance pipelineRunManager.updateRunInstance(longId, instance); autoscalerService.registerDisks(longId, instance); Instant end = Instant.now(); diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java index 242bf47b73..e98f8acb29 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java @@ -164,7 +164,7 @@ public void registerDisks(final Long runId, final RunInstance instance) { private void registerNodeDisks(long runId, List disks) { PipelineRun run = runCRUDService.loadRunById(runId); String nodeId = run.getInstance().getNodeId(); - LocalDateTime creationDate = DateUtils.convertDateToLocalDateTime(run.getStartDate()); + LocalDateTime creationDate = run.getInstanceStartDateTime(); List requests = DiskRegistrationRequest.from(disks); nodeDiskManager.register(nodeId, creationDate, requests); } diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java index e53aa7ebd4..2b24ea9fcb 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java @@ -24,6 +24,7 @@ import com.epam.pipeline.entity.cluster.pool.filter.instancefilter.PoolInstanceFilterType; import com.epam.pipeline.entity.pipeline.PipelineRun; import com.epam.pipeline.entity.pipeline.RunInstance; +import com.epam.pipeline.entity.utils.DateUtils; import com.epam.pipeline.manager.cloud.CloudFacade; import com.epam.pipeline.manager.cluster.KubernetesConstants; import com.epam.pipeline.manager.cluster.autoscale.filter.PoolFilterHandler; @@ -183,6 +184,7 @@ private boolean reassignInstance(final String newNodeId, final RunInstance reassignedInstance = StringUtils.isBlank(instance.getNodeId()) ? cloudFacade.describeInstance(runId, instance) : instance; reassignedInstance.setPoolId(instance.getPoolId()); + reassignedInstance.setStartDate(DateUtils.now()); pipelineRunManager.updateRunInstance(runId, reassignedInstance); final List disks = cloudFacade.loadDisks(reassignedInstance.getCloudRegionId(), runId); diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCore.java b/api/src/main/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCore.java index c77a10947d..69f9cc7da8 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCore.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCore.java @@ -17,9 +17,9 @@ package com.epam.pipeline.manager.cluster.costs; import com.epam.pipeline.entity.pipeline.PipelineRun; -import com.epam.pipeline.entity.utils.DateUtils; import com.epam.pipeline.manager.pipeline.PipelineRunCRUDService; import com.epam.pipeline.manager.pipeline.PipelineRunManager; +import com.epam.pipeline.utils.RunDurationUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.javacrumbs.shedlock.core.SchedulerLock; @@ -28,11 +28,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @@ -79,17 +77,7 @@ private BigDecimal estimatePriceForRun(final PipelineRun run) { return BigDecimal.ZERO; } return run.getPricePerHour() - .multiply(durationInMinutes(run)) + .multiply(BigDecimal.valueOf(RunDurationUtils.getBillableDuration(run).toMinutes())) .divide(BigDecimal.valueOf(MINUTES_IN_HOUR), DIVIDE_SCALE, RoundingMode.HALF_UP); } - - private BigDecimal durationInMinutes(final PipelineRun run) { - if (Objects.isNull(run.getStartDate())) { - return BigDecimal.ZERO; - } - - final Date pipelineEnd = Objects.isNull(run.getEndDate()) ? DateUtils.now() : run.getEndDate(); - final long runDurationMs = pipelineEnd.getTime() - run.getStartDate().getTime(); - return new BigDecimal(TimeUnit.MINUTES.convert(runDurationMs, TimeUnit.MILLISECONDS)); - } } diff --git a/api/src/main/java/com/epam/pipeline/mapper/PipelineRunMapper.java b/api/src/main/java/com/epam/pipeline/mapper/PipelineRunMapper.java index ecf427ab62..3ec15e31b5 100644 --- a/api/src/main/java/com/epam/pipeline/mapper/PipelineRunMapper.java +++ b/api/src/main/java/com/epam/pipeline/mapper/PipelineRunMapper.java @@ -16,12 +16,11 @@ package com.epam.pipeline.mapper; -import java.time.Duration; import java.util.Map; import com.epam.pipeline.config.JsonMapper; import com.epam.pipeline.entity.pipeline.PipelineRun; -import com.epam.pipeline.entity.utils.DateUtils; +import com.epam.pipeline.utils.RunDurationUtils; import org.apache.commons.lang3.StringUtils; public final class PipelineRunMapper { @@ -64,6 +63,6 @@ public static Map map(PipelineRun run) { } private static long overallDurationOf(PipelineRun run) { - return Duration.between(run.getStartDate().toInstant(), DateUtils.now().toInstant()).abs().getSeconds(); + return RunDurationUtils.getOverallDuration(run).getSeconds(); } } diff --git a/api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java b/api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java new file mode 100644 index 0000000000..12100b8e20 --- /dev/null +++ b/api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java @@ -0,0 +1,25 @@ +package com.epam.pipeline.utils; + +import com.epam.pipeline.entity.pipeline.PipelineRun; +import com.epam.pipeline.entity.utils.DateUtils; + +import java.time.Duration; +import java.util.Date; +import java.util.Optional; + +public class RunDurationUtils { + + public static Duration getOverallDuration(final PipelineRun run) { + return durationBetween(run.getStartDate(), run.getEndDate()); + } + + public static Duration getBillableDuration(final PipelineRun run) { + return durationBetween(run.getInstanceStartDate(), run.getEndDate()); + } + + private static Duration durationBetween(final Date from, final Date to) { + final Date end = Optional.ofNullable(to).orElseGet(DateUtils::now); + final Date start = Optional.ofNullable(from).orElse(end); + return Duration.ofMillis(end.getTime() - start.getTime()).abs(); + } +} diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/StorageBillingMapperTest.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/StorageBillingMapperTest.java index fac85c9666..39825a54b5 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/StorageBillingMapperTest.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/StorageBillingMapperTest.java @@ -61,7 +61,7 @@ public class StorageBillingMapperTest { private static final long TEST_USAGE_BYTES = 600; private static final List TEST_GROUPS = Arrays.asList(TEST_GROUP_1, TEST_GROUP_2); private static final Date TEST_JAVA_DATE = DateUtils.now(); - private static final LocalDate TEST_DATE = DateUtils.toLocalDateTime(TEST_JAVA_DATE).toLocalDate(); + private static final LocalDate TEST_DATE = DateUtils.convertDateToLocalDateTime(TEST_JAVA_DATE).toLocalDate(); private static final String TEST_STORAGE_NAME = "storage_name"; private static final String TEST_STORAGE_PATH = "storage_path"; From 581ff140adb5c42e3dd2f275c384fcf92c521df3 Mon Sep 17 00:00:00 2001 From: Andrey Tsibin Date: Fri, 14 Apr 2023 16:43:41 +0300 Subject: [PATCH 3/6] Use instance start date in billing --- .../RunToBillingRequestConverter.java | 81 +-- .../service/impl/TestUtils.java | 10 +- .../RunToBillingRequestConverterImplTest.java | 560 ++++++++++-------- .../impl/mapper/RunBillingMapperTest.java | 2 +- .../epam/pipeline/entity/utils/DateUtils.java | 10 +- 5 files changed, 360 insertions(+), 303 deletions(-) diff --git a/billing-report-agent/src/main/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverter.java b/billing-report-agent/src/main/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverter.java index 428b2eef23..94dc1f9b90 100644 --- a/billing-report-agent/src/main/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverter.java +++ b/billing-report-agent/src/main/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverter.java @@ -93,16 +93,14 @@ protected Collection convertRunToBillings( final LocalDateTime syncStart) { final PipelineRun pipelineRun = runContainer.getEntity().getPipelineRun(); if (previousSync != null && pipelineRun.getStatus().isFinal() && - pipelineRun.getEndDate() != null && - getEnd(pipelineRun).isBefore(previousSync)) { + getEnd(pipelineRun).orElse(LocalDateTime.MAX).isBefore(previousSync)) { log.debug("Run {} [{} - {}] was not active in period {} - {}.", pipelineRun.getId(), pipelineRun.getStartDate(), pipelineRun.getEndDate(), previousSync, syncStart); return Collections.emptyList(); } final RunPrice price = getPrice(runContainer); - final List statuses = adjustStatuses(pipelineRun, - previousSync, syncStart); + final List statuses = adjustStatuses(pipelineRun, previousSync, syncStart); return createBillingsForPeriod(runContainer.getEntity(), price, statuses).stream() .filter(this::isNotEmpty) @@ -117,32 +115,48 @@ private boolean isNotEmpty(final PipelineRunBillingInfo billing) { } protected List adjustStatuses(final PipelineRun run, - final LocalDateTime previousSync, - final LocalDateTime syncStart) { + final LocalDateTime prevSync, + final LocalDateTime currSync) { + final LocalDateTime syncStart = toStartOfDay(prevSync).orElse(LocalDateTime.MIN); + final LocalDateTime syncEnd = toStartOfDay(currSync).orElseThrow(this::throwMissingSyncEnd); + final LocalDateTime runStart = getStart(run).orElse(LocalDateTime.MAX); + final LocalDateTime runEnd = getEnd(run).orElse(LocalDateTime.MAX); + if (runEnd.isBefore(syncStart) || runEnd.isBefore(runStart) + || syncEnd.isBefore(syncStart) || syncEnd.isBefore(runStart)) { + return getInactiveStatuses(run, syncStart); + } + final LocalDateTime start = max(syncStart, runStart); + final LocalDateTime end = min(syncEnd, runEnd); final List statuses = run.getRunStatuses(); - final LocalDateTime start = getBillingPeriodStart(previousSync); - final LocalDateTime end = getBillingPeriodEnd(syncStart); - return CollectionUtils.isNotEmpty(statuses) - ? getAdjustedStatuses(run, statuses, start, end) - : getDefaultStatuses(run, start, end); + if (CollectionUtils.isEmpty(statuses)) { + return getActiveStatuses(run, start, end); + } + return getAdjustedStatuses(run, statuses, start, end); } - private LocalDateTime getBillingPeriodStart(final LocalDateTime periodStart) { - return toStartOfDay(periodStart).orElse(LocalDateTime.MIN); + private List getInactiveStatuses(final PipelineRun run, final LocalDateTime start) { + return Collections.singletonList( + new RunStatus(run.getId(), TaskStatus.STOPPED, start)); } - private LocalDateTime getBillingPeriodEnd(final LocalDateTime periodEnd) { - return toStartOfDay(periodEnd) - .orElseThrow(() -> new IllegalArgumentException("Billing period end date should be provided.")); + private List getActiveStatuses(final PipelineRun run, + final LocalDateTime start, + final LocalDateTime end) { + return Arrays.asList( + new RunStatus(run.getId(), TaskStatus.RUNNING, start), + new RunStatus(run.getId(), TaskStatus.STOPPED, end)); + } + private IllegalArgumentException throwMissingSyncEnd() { + return new IllegalArgumentException("Billing period end date should be provided."); } - private Optional toStartOfDay(final LocalDateTime previousSync) { - return Optional.ofNullable(previousSync) + private Optional toStartOfDay(final LocalDateTime date) { + return Optional.ofNullable(date) .map(LocalDateTime::toLocalDate) .map(LocalDate::atStartOfDay); } - private List getAdjustedStatuses(final PipelineRun run, final List statuses, + private List getAdjustedStatuses(final PipelineRun run, final List statuses, final LocalDateTime start, final LocalDateTime end) { final List sortedStatuses = statuses.stream() .sorted(Comparator.comparing(RunStatus::getTimestamp)) @@ -185,28 +199,28 @@ private int getLastOverlappingStatusIndex(final LocalDateTime end, final List getStart(final PipelineRun run) { + return getDate(run, PipelineRun::getInstanceStartDate); } - private LocalDateTime getEnd(final PipelineRun run) { - return getDate(run, PipelineRun::getEndDate).orElse(LocalDateTime.MAX); + private Optional getEnd(final PipelineRun run) { + return getDate(run, PipelineRun::getEndDate); } private Optional getDate(final PipelineRun run, final Function function) { - return Optional.ofNullable(run).map(function).map(DateUtils::toLocalDateTime); + return Optional.ofNullable(run).map(function).map(DateUtils::convertDateToLocalDateTime); } private LocalDateTime min(final LocalDateTime first, final LocalDateTime second) { @@ -217,17 +231,6 @@ private LocalDateTime max(final LocalDateTime first, final LocalDateTime second) return second.isAfter(first) ? second : first; } - private List getDefaultStatuses(final PipelineRun run, final LocalDateTime start, - final LocalDateTime end) { - final LocalDateTime runStart = getStart(run); - final LocalDateTime runEnd = getEnd(run); - return runEnd.isBefore(start) || runStart.isAfter(end) - ? Collections.singletonList(new RunStatus(run.getId(), TaskStatus.STOPPED, start)) - : Arrays.asList( - new RunStatus(run.getId(), TaskStatus.RUNNING, max(start, runStart)), - new RunStatus(run.getId(), TaskStatus.STOPPED, min(end, runEnd))); - } - private RunPrice getPrice(final EntityContainer runContainer) { final BigDecimal pricePerHour = getUserPrice(runContainer, PipelineRun::getPricePerHour); final BigDecimal computePricePerHour = getBillingPrice(runContainer, PipelineRun::getComputePricePerHour); diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java index 7e740d25bf..906bebca61 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java @@ -22,6 +22,7 @@ import com.epam.pipeline.entity.pipeline.TaskStatus; import com.epam.pipeline.entity.region.AbstractCloudRegion; import com.epam.pipeline.entity.region.AwsRegion; +import com.epam.pipeline.entity.utils.DateUtils; import com.fasterxml.jackson.core.JsonFactory; import org.apache.commons.collections.CollectionUtils; import org.elasticsearch.common.Strings; @@ -36,6 +37,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Map; +import java.util.Optional; public final class TestUtils { @@ -79,13 +81,19 @@ public static PipelineRun createTestPipelineRun(final Long runId, final Long pip return run; } - public static RunInstance createTestInstance(final Long regionId, final String nodeType) { + public static RunInstance createTestInstance(final Long regionId, final String nodeType, + final LocalDateTime date) { final RunInstance instance = new RunInstance(); instance.setCloudRegionId(regionId); instance.setNodeType(nodeType); + instance.setStartDate(Optional.ofNullable(date).map(DateUtils::convertLocalDateTimeToDate).orElse(null)); return instance; } + public static RunInstance createTestInstance(final Long regionId, final String nodeType) { + return createTestInstance(regionId, nodeType, null); + } + public static AbstractCloudRegion createTestRegion(final Long regionId) { final AwsRegion region = new AwsRegion(); region.setId(regionId); diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java index 3088fc1137..78f762f95e 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java @@ -27,20 +27,20 @@ import com.epam.pipeline.billingreportagent.service.impl.mapper.RunBillingMapper; import com.epam.pipeline.entity.cluster.NodeDisk; import com.epam.pipeline.entity.pipeline.PipelineRun; +import com.epam.pipeline.entity.pipeline.RunInstance; import com.epam.pipeline.entity.pipeline.TaskStatus; import com.epam.pipeline.entity.pipeline.run.RunStatus; import com.epam.pipeline.entity.user.PipelineUser; +import com.epam.pipeline.entity.utils.DateUtils; import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.index.IndexRequest; -import org.junit.Assert; import org.junit.jupiter.api.Test; import java.math.BigDecimal; -import java.time.Instant; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; -import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -53,7 +53,8 @@ import java.util.stream.Collectors; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @SuppressWarnings("checkstyle:magicnumber") @@ -86,10 +87,47 @@ public class RunToBillingRequestConverterImplTest { private final RunToBillingRequestConverter converter = new RunToBillingRequestConverter(new RunBillingMapper(BILLING_CENTER_KEY)); + @Test + public void convertShouldReturnElasticRequests() { + final LocalDateTime prevSync = LocalDate.of(2019, 12, 4).atStartOfDay(); + final LocalDateTime syncStart = LocalDate.of(2019, 12, 5).atStartOfDay(); + + final PipelineRun run = TestUtils.createTestPipelineRun(RUN_ID, PIPELINE_ID, TOOL_IMAGE, PRICE, + TestUtils.createTestInstance(REGION_ID, NODE_TYPE, + prevSync)); + + final EntityContainer runContainer = + EntityContainer.builder() + .entity(runEntity(run, Collections.emptyList())) + .owner(testUserWithMetadata) + .region(TestUtils.createTestRegion(REGION_ID)) + .build(); + + final List billings = + converter.convertEntityToRequests(runContainer, TestUtils.RUN_BILLING_PREFIX, prevSync, syncStart); + assertEquals(1, billings.size()); + + final DocWriteRequest billing = billings.get(0); + final Map requestFieldsMap = ((IndexRequest) billing).sourceAsMap(); + final String expectedIndex = TestUtils.buildBillingIndex(TestUtils.RUN_BILLING_PREFIX, prevSync); + assertEquals(expectedIndex, billing.index()); + assertEquals(run.getId().intValue(), requestFieldsMap.get("run_id")); + assertEquals(ResourceType.COMPUTE.toString(), requestFieldsMap.get("resource_type")); + assertEquals(run.getPipelineId().intValue(), requestFieldsMap.get("pipeline")); + assertEquals(run.getDockerImage(), requestFieldsMap.get("tool")); + assertEquals(run.getInstance().getNodeType(), requestFieldsMap.get("instance_type")); + assertEquals(9600, requestFieldsMap.get("cost")); + assertEquals(1440, requestFieldsMap.get("usage_minutes")); + assertEquals(PRICE.unscaledValue().intValue(), requestFieldsMap.get("run_price")); + assertEquals(run.getInstance().getCloudRegionId().intValue(), requestFieldsMap.get("cloudRegionId")); + assertEquals(USER_NAME, requestFieldsMap.get("owner")); + TestUtils.verifyStringArray(USER_GROUPS, requestFieldsMap.get("groups")); + } @Test - public void shouldConvertToBillingsWithOneFinalStatus() { - final PipelineRun run = run(status(TaskStatus.STOPPED, LocalDateTime.of(2019, 12, 4, 15, 0))); + public void convertShouldReturnBillingsForSingleRunningPeriod() { + final PipelineRun run = run(LocalDateTime.of(2019, 12, 4, 14, 55), + status(TaskStatus.STOPPED, LocalDateTime.of(2019, 12, 4, 15, 0))); run.setStartDate(Date.from( LocalDateTime.of(2019, 12, 4, 10, 0) .atZone(ZoneId.of("Z")) @@ -103,12 +141,12 @@ public void shouldConvertToBillingsWithOneFinalStatus() { converter.convertRunToBillings(runContainer, LocalDate.of(2019, 12, 4).atStartOfDay(), LocalDate.of(2019, 12, 5).atStartOfDay()); - Assert.assertEquals(1, billings.size()); + assertEquals(1, billings.size()); } @Test - public void convertRunToBillings() { - final PipelineRun run = run( + public void convertShouldReturnBillingsForMultipleRunningAndPausedPeriods() { + final PipelineRun run = run(LocalDateTime.of(2019, 12, 1, 11, 55), status(TaskStatus.RUNNING, LocalDateTime.of(2019, 12, 1, 12, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2019, 12, 1, 13, 0)), status(TaskStatus.RUNNING, LocalDateTime.of(2019, 12, 1, 18, 0)), @@ -125,26 +163,26 @@ public void convertRunToBillings() { converter.convertRunToBillings(runContainer, LocalDate.of(2019, 12, 1).atStartOfDay(), LocalDate.of(2019, 12, 5).atStartOfDay()); - Assert.assertEquals(4, billings.size()); + assertEquals(4, billings.size()); final Map reports = billings.stream().collect(Collectors.toMap(PipelineRunBillingInfo::getDate, Function.identity())); - Assert.assertEquals(1200, reports.get(LocalDate.of(2019, 12, 1)).getCost().longValue()); - Assert.assertEquals(4800, reports.get(LocalDate.of(2019, 12, 2)).getCost().longValue()); - Assert.assertEquals(6000, reports.get(LocalDate.of(2019, 12, 3)).getCost().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2019, 12, 4)).getCost().longValue()); - Assert.assertEquals(180, reports.get(LocalDate.of(2019, 12, 1)).getUsageMinutes().longValue()); - Assert.assertEquals(720, reports.get(LocalDate.of(2019, 12, 2)).getUsageMinutes().longValue()); - Assert.assertEquals(900, reports.get(LocalDate.of(2019, 12, 3)).getUsageMinutes().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2019, 12, 4)).getUsageMinutes().longValue()); - Assert.assertEquals(540, reports.get(LocalDate.of(2019, 12, 1)).getPausedMinutes().longValue()); - Assert.assertEquals(720, reports.get(LocalDate.of(2019, 12, 2)).getPausedMinutes().longValue()); - Assert.assertEquals(540, reports.get(LocalDate.of(2019, 12, 3)).getPausedMinutes().longValue()); - Assert.assertEquals(900, reports.get(LocalDate.of(2019, 12, 4)).getPausedMinutes().longValue()); - } - - @Test - public void convertRunWithNoStatusesToBilling() { - final PipelineRun run = run(); + assertEquals(1200, reports.get(LocalDate.of(2019, 12, 1)).getCost().longValue()); + assertEquals(4800, reports.get(LocalDate.of(2019, 12, 2)).getCost().longValue()); + assertEquals(6000, reports.get(LocalDate.of(2019, 12, 3)).getCost().longValue()); + assertEquals(0, reports.get(LocalDate.of(2019, 12, 4)).getCost().longValue()); + assertEquals(180, reports.get(LocalDate.of(2019, 12, 1)).getUsageMinutes().longValue()); + assertEquals(720, reports.get(LocalDate.of(2019, 12, 2)).getUsageMinutes().longValue()); + assertEquals(900, reports.get(LocalDate.of(2019, 12, 3)).getUsageMinutes().longValue()); + assertEquals(0, reports.get(LocalDate.of(2019, 12, 4)).getUsageMinutes().longValue()); + assertEquals(540, reports.get(LocalDate.of(2019, 12, 1)).getPausedMinutes().longValue()); + assertEquals(720, reports.get(LocalDate.of(2019, 12, 2)).getPausedMinutes().longValue()); + assertEquals(540, reports.get(LocalDate.of(2019, 12, 3)).getPausedMinutes().longValue()); + assertEquals(900, reports.get(LocalDate.of(2019, 12, 4)).getPausedMinutes().longValue()); + } + + @Test + public void convertShouldReturnBillingsIfThereAreNoStatuses() { + final PipelineRun run = run(LocalDateTime.of(2019, 12, 3, 0, 0)); run.setPricePerHour(BigDecimal.valueOf(4, 2)); final EntityContainer runContainer = EntityContainer.builder() .entity(runEntity(run, Collections.emptyList())) @@ -154,53 +192,47 @@ public void convertRunWithNoStatusesToBilling() { converter.convertRunToBillings(runContainer, LocalDate.of(2019, 12, 4).atStartOfDay(), LocalDate.of(2019, 12, 5).atStartOfDay()); - Assert.assertEquals(1, billings.size()); + assertEquals(1, billings.size()); final Map reports = billings.stream().collect(Collectors.toMap(PipelineRunBillingInfo::getDate, Function.identity())); - Assert.assertEquals(9600, reports.get(LocalDate.of(2019, 12, 4)).getCost().longValue()); - Assert.assertEquals(1440, reports.get(LocalDate.of(2019, 12, 4)).getUsageMinutes().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2019, 12, 4)).getPausedMinutes().longValue()); + assertEquals(9600, reports.get(LocalDate.of(2019, 12, 4)).getCost().longValue()); + assertEquals(1440, reports.get(LocalDate.of(2019, 12, 4)).getUsageMinutes().longValue()); + assertEquals(0, reports.get(LocalDate.of(2019, 12, 4)).getPausedMinutes().longValue()); } @Test - public void testRunConverting() { - final PipelineRun run = TestUtils.createTestPipelineRun(RUN_ID, PIPELINE_ID, TOOL_IMAGE, PRICE, - TestUtils.createTestInstance(REGION_ID, NODE_TYPE)); + public void convertShouldReturnBillingsForNewFashionedRunForSingleRunningPeriod() { + final PipelineRun run = run(LocalDateTime.of(2020, 5, 21, 11, 55), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 21, 12, 0))); + run.setPricePerHour(new BigDecimal("0.04")); + run.setComputePricePerHour(new BigDecimal("0.02000")); + run.setDiskPricePerHour(new BigDecimal("0.00100")); - final EntityContainer runContainer = - EntityContainer.builder() - .entity(runEntity(run, Collections.emptyList())) - .owner(testUserWithMetadata) - .region(TestUtils.createTestRegion(REGION_ID)) + final List disks = new ArrayList<>(); + disks.add(disk(20L, LocalDateTime.of(2020, 5, 21, 12, 0))); + disks.add(disk(20L, LocalDateTime.of(2020, 5, 21, 12, 0))); + final EntityContainer runContainer = EntityContainer.builder() + .entity(runEntity(run, disks)) .build(); - - final LocalDateTime prevSync = LocalDate.of(2019, 12, 4).atStartOfDay(); - final LocalDateTime syncStart = LocalDate.of(2019, 12, 5).atStartOfDay(); - final List billings = - converter.convertEntityToRequests(runContainer, TestUtils.RUN_BILLING_PREFIX, prevSync, syncStart); - Assert.assertEquals(1, billings.size()); - - final DocWriteRequest billing = billings.get(0); - final Map requestFieldsMap = ((IndexRequest) billing).sourceAsMap(); - final String expectedIndex = TestUtils.buildBillingIndex(TestUtils.RUN_BILLING_PREFIX, prevSync); - Assert.assertEquals(expectedIndex, billing.index()); - Assert.assertEquals(run.getId().intValue(), requestFieldsMap.get("run_id")); - Assert.assertEquals(ResourceType.COMPUTE.toString(), requestFieldsMap.get("resource_type")); - Assert.assertEquals(run.getPipelineId().intValue(), requestFieldsMap.get("pipeline")); - Assert.assertEquals(run.getDockerImage(), requestFieldsMap.get("tool")); - Assert.assertEquals(run.getInstance().getNodeType(), requestFieldsMap.get("instance_type")); - Assert.assertEquals(9600, requestFieldsMap.get("cost")); - Assert.assertEquals(1440, requestFieldsMap.get("usage_minutes")); - Assert.assertEquals(PRICE.unscaledValue().intValue(), requestFieldsMap.get("run_price")); - Assert.assertEquals(run.getInstance().getCloudRegionId().intValue(), requestFieldsMap.get("cloudRegionId")); - Assert.assertEquals(USER_NAME, requestFieldsMap.get("owner")); - TestUtils.verifyStringArray(USER_GROUPS, requestFieldsMap.get("groups")); + final Collection billings = + converter.convertRunToBillings(runContainer, + LocalDate.of(2020, 5, 21).atStartOfDay(), + LocalDate.of(2020, 5, 23).atStartOfDay()); + assertEquals(2, billings.size()); + final Map reports = + billings.stream().collect(Collectors.toMap(PipelineRunBillingInfo::getDate, Function.identity())); + assertEquals(7200, reports.get(LocalDate.of(2020, 5, 21)).getCost().longValue()); + assertEquals(14400, reports.get(LocalDate.of(2020, 5, 22)).getCost().longValue()); + assertEquals(720, reports.get(LocalDate.of(2020, 5, 21)).getUsageMinutes().longValue()); + assertEquals(1440, reports.get(LocalDate.of(2020, 5, 22)).getUsageMinutes().longValue()); + assertEquals(0, reports.get(LocalDate.of(2020, 5, 21)).getPausedMinutes().longValue()); + assertEquals(0, reports.get(LocalDate.of(2020, 5, 22)).getPausedMinutes().longValue()); } @Test - void testConvertNewFashionedRunToBillings() { - final PipelineRun run = run( + public void convertShouldReturnBillingsForNewFashionedRunForMultipleRunningAndPausedPeriods() { + final PipelineRun run = run(LocalDateTime.of(2020, 5, 21, 11, 55), status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 21, 12, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 21, 13, 0)), status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 21, 18, 0)), @@ -226,29 +258,29 @@ void testConvertNewFashionedRunToBillings() { converter.convertRunToBillings(runContainer, LocalDate.of(2020, 5, 21).atStartOfDay(), LocalDate.of(2020, 5, 26).atStartOfDay()); - Assert.assertEquals(5, billings.size()); + assertEquals(5, billings.size()); final Map reports = billings.stream().collect(Collectors.toMap(PipelineRunBillingInfo::getDate, Function.identity())); - Assert.assertEquals(6300, reports.get(LocalDate.of(2020, 5, 21)).getCost().longValue()); - Assert.assertEquals(21600, reports.get(LocalDate.of(2020, 5, 22)).getCost().longValue()); - Assert.assertEquals(24000, reports.get(LocalDate.of(2020, 5, 23)).getCost().longValue()); - Assert.assertEquals(28200, reports.get(LocalDate.of(2020, 5, 24)).getCost().longValue()); - Assert.assertEquals(21000, reports.get(LocalDate.of(2020, 5, 25)).getCost().longValue()); - Assert.assertEquals(240, reports.get(LocalDate.of(2020, 5, 21)).getUsageMinutes().longValue()); - Assert.assertEquals(720, reports.get(LocalDate.of(2020, 5, 22)).getUsageMinutes().longValue()); - Assert.assertEquals(1440, reports.get(LocalDate.of(2020, 5, 23)).getUsageMinutes().longValue()); - Assert.assertEquals(900, reports.get(LocalDate.of(2020, 5, 24)).getUsageMinutes().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2020, 5, 25)).getUsageMinutes().longValue()); - Assert.assertEquals(480, reports.get(LocalDate.of(2020, 5, 21)).getPausedMinutes().longValue()); - Assert.assertEquals(720, reports.get(LocalDate.of(2020, 5, 22)).getPausedMinutes().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2020, 5, 23)).getPausedMinutes().longValue()); - Assert.assertEquals(540, reports.get(LocalDate.of(2020, 5, 24)).getPausedMinutes().longValue()); - Assert.assertEquals(900, reports.get(LocalDate.of(2020, 5, 25)).getPausedMinutes().longValue()); - } - - @Test - void testConvertOldFashionedPausedRunToBillings() { - final PipelineRun run = run( + assertEquals(6300, reports.get(LocalDate.of(2020, 5, 21)).getCost().longValue()); + assertEquals(21600, reports.get(LocalDate.of(2020, 5, 22)).getCost().longValue()); + assertEquals(24000, reports.get(LocalDate.of(2020, 5, 23)).getCost().longValue()); + assertEquals(28200, reports.get(LocalDate.of(2020, 5, 24)).getCost().longValue()); + assertEquals(21000, reports.get(LocalDate.of(2020, 5, 25)).getCost().longValue()); + assertEquals(240, reports.get(LocalDate.of(2020, 5, 21)).getUsageMinutes().longValue()); + assertEquals(720, reports.get(LocalDate.of(2020, 5, 22)).getUsageMinutes().longValue()); + assertEquals(1440, reports.get(LocalDate.of(2020, 5, 23)).getUsageMinutes().longValue()); + assertEquals(900, reports.get(LocalDate.of(2020, 5, 24)).getUsageMinutes().longValue()); + assertEquals(0, reports.get(LocalDate.of(2020, 5, 25)).getUsageMinutes().longValue()); + assertEquals(480, reports.get(LocalDate.of(2020, 5, 21)).getPausedMinutes().longValue()); + assertEquals(720, reports.get(LocalDate.of(2020, 5, 22)).getPausedMinutes().longValue()); + assertEquals(0, reports.get(LocalDate.of(2020, 5, 23)).getPausedMinutes().longValue()); + assertEquals(540, reports.get(LocalDate.of(2020, 5, 24)).getPausedMinutes().longValue()); + assertEquals(900, reports.get(LocalDate.of(2020, 5, 25)).getPausedMinutes().longValue()); + } + + @Test + public void convertShouldReturnBillingsForOldFashionedPausedRun() { + final PipelineRun run = run(LocalDateTime.of(2020, 5, 21, 11, 55), status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 21, 12, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 21, 13, 0))); run.setPricePerHour(new BigDecimal("0.04")); @@ -265,67 +297,93 @@ void testConvertOldFashionedPausedRunToBillings() { converter.convertRunToBillings(runContainer, LocalDate.of(2020, 5, 21).atStartOfDay(), LocalDate.of(2020, 5, 23).atStartOfDay()); - Assert.assertEquals(2, billings.size()); + assertEquals(2, billings.size()); final Map reports = billings.stream().collect(Collectors.toMap(PipelineRunBillingInfo::getDate, Function.identity())); - Assert.assertEquals(5000, reports.get(LocalDate.of(2020, 5, 21)).getCost().longValue()); - Assert.assertEquals(9600, reports.get(LocalDate.of(2020, 5, 22)).getCost().longValue()); - Assert.assertEquals(60, reports.get(LocalDate.of(2020, 5, 21)).getUsageMinutes().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2020, 5, 22)).getUsageMinutes().longValue()); - Assert.assertEquals(660, reports.get(LocalDate.of(2020, 5, 21)).getPausedMinutes().longValue()); - Assert.assertEquals(1440, reports.get(LocalDate.of(2020, 5, 22)).getPausedMinutes().longValue()); + assertEquals(5000, reports.get(LocalDate.of(2020, 5, 21)).getCost().longValue()); + assertEquals(9600, reports.get(LocalDate.of(2020, 5, 22)).getCost().longValue()); + assertEquals(60, reports.get(LocalDate.of(2020, 5, 21)).getUsageMinutes().longValue()); + assertEquals(0, reports.get(LocalDate.of(2020, 5, 22)).getUsageMinutes().longValue()); + assertEquals(660, reports.get(LocalDate.of(2020, 5, 21)).getPausedMinutes().longValue()); + assertEquals(1440, reports.get(LocalDate.of(2020, 5, 22)).getPausedMinutes().longValue()); } @Test - void testConvertNewFashionedRunningRunToBillings() { - final PipelineRun run = run(status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 21, 12, 0))); - run.setPricePerHour(new BigDecimal("0.04")); - run.setComputePricePerHour(new BigDecimal("0.02000")); - run.setDiskPricePerHour(new BigDecimal("0.00100")); + public void testAdjustStatusesForStartedStatusRun() { + final PipelineRun run = run( + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0))); - final List disks = new ArrayList<>(); - disks.add(disk(20L, LocalDateTime.of(2020, 5, 21, 12, 0))); - disks.add(disk(20L, LocalDateTime.of(2020, 5, 21, 12, 0))); - final EntityContainer runContainer = EntityContainer.builder() - .entity(runEntity(run, disks)) - .build(); - final Collection billings = - converter.convertRunToBillings(runContainer, - LocalDate.of(2020, 5, 21).atStartOfDay(), - LocalDate.of(2020, 5, 23).atStartOfDay()); - Assert.assertEquals(2, billings.size()); - final Map reports = - billings.stream().collect(Collectors.toMap(PipelineRunBillingInfo::getDate, Function.identity())); - Assert.assertEquals(7200, reports.get(LocalDate.of(2020, 5, 21)).getCost().longValue()); - Assert.assertEquals(14400, reports.get(LocalDate.of(2020, 5, 22)).getCost().longValue()); - Assert.assertEquals(720, reports.get(LocalDate.of(2020, 5, 21)).getUsageMinutes().longValue()); - Assert.assertEquals(1440, reports.get(LocalDate.of(2020, 5, 22)).getUsageMinutes().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2020, 5, 21)).getPausedMinutes().longValue()); - Assert.assertEquals(0, reports.get(LocalDate.of(2020, 5, 22)).getPausedMinutes().longValue()); + final List adjustedStatuses = converter.adjustStatuses(run, + LocalDate.of(2020, 5, 20).atStartOfDay(), + LocalDate.of(2020, 5, 21).atStartOfDay()); + + assertRunsActivityStats(adjustedStatuses, + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 21, 0, 0, 0))); } @Test - public void testAdjustStatusesForStartedRun() { + public void testAdjustStatusesForStartedStatusAndEarlyStartedDateRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0))); + LocalDateTime.of(2020, 5, 20, 11, 50, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0))); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), LocalDate.of(2020, 5, 21).atStartOfDay()); assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0)), status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 21, 0, 0, 0))); } @Test - void testAdjustStatusesForStartedAndStoppedRun() { + public void testAdjustStatusesForStartedStatusAndNoStartedDateRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 55, 0), NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0))); + + final List adjustedStatuses = converter.adjustStatuses(run, + LocalDate.of(2020, 5, 20).atStartOfDay(), + LocalDate.of(2020, 5, 21).atStartOfDay()); + + assertRunsActivityStats(adjustedStatuses, + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); + } + + @Test + public void testAdjustStatusesForNoStatusesAndNoStartedDateRun() { + final PipelineRun run = run( + NO_DATE); + + final List adjustedStatuses = converter.adjustStatuses(run, + LocalDate.of(2020, 5, 20).atStartOfDay(), + LocalDate.of(2020, 5, 21).atStartOfDay()); + + assertRunsActivityStats(adjustedStatuses, + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); + } + + @Test + public void testAdjustStatusesForNoStatusesAndPreviouslyStoppedDateRun() { + final PipelineRun run = run( + NO_DATE, + LocalDateTime.of(2020, 5, 19, 14, 0, 0)); + + final List adjustedStatuses = converter.adjustStatuses(run, + LocalDate.of(2020, 5, 20).atStartOfDay(), + LocalDate.of(2020, 5, 21).atStartOfDay()); + + assertRunsActivityStats(adjustedStatuses, + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); + } + + @Test + public void testAdjustStatusesForStartedStoppedStatusesRun() { + final PipelineRun run = run( + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0)), status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 14, 0, 0))); final List adjustedStatuses = converter.adjustStatuses(run, @@ -338,11 +396,26 @@ void testAdjustStatusesForStartedAndStoppedRun() { } @Test - public void testAdjustStatusesForStartedAndPausedRun() { + public void testAdjustStatusesForStartedStatusAndStoppedDateRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 55, 0), - NO_DATE, + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + LocalDateTime.of(2020, 5, 20, 14, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0))); + + final List adjustedStatuses = converter.adjustStatuses(run, + LocalDate.of(2020, 5, 20).atStartOfDay(), + LocalDate.of(2020, 5, 21).atStartOfDay()); + + assertRunsActivityStats(adjustedStatuses, status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 14, 0, 0))); + } + + @Test + public void testAdjustStatusesForStartedPausedStatusesRun() { + final PipelineRun run = run( + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 14, 0, 0))); final List adjustedStatuses = converter.adjustStatuses(run, @@ -356,11 +429,10 @@ public void testAdjustStatusesForStartedAndPausedRun() { } @Test - public void testAdjustStatusesForStartedAndPausedAndResumedRun() { + public void testAdjustStatusesForStartedPausedResumedStatusesRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 14, 0, 0)), status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 16, 0, 0))); @@ -376,11 +448,10 @@ public void testAdjustStatusesForStartedAndPausedAndResumedRun() { } @Test - public void testAdjustStatusesForStartedAndPausedAndStoppedRun() { + public void testAdjustStatusesForStartedPausedStoppedStatusesRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 14, 0, 0)), status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 18, 0, 0))); @@ -395,11 +466,10 @@ public void testAdjustStatusesForStartedAndPausedAndStoppedRun() { } @Test - public void testAdjustStatusesForPreviouslyStartedAndStoppedRun() { + public void testAdjustStatusesForPreviouslyStartedAndStoppedStatusesRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 10, 0, 0)), + LocalDateTime.of(2020, 5, 19, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 11, 55, 0)), status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 15, 0, 0))); final List adjustedStatuses = converter.adjustStatuses(run, @@ -412,11 +482,41 @@ public void testAdjustStatusesForPreviouslyStartedAndStoppedRun() { } @Test - public void testAdjustStatusesForPreviouslyStartedAndPreviouslyPausedRun() { + public void testAdjustStatusesForPreviouslyStartedStoppedRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 12, 0, 0)), + LocalDateTime.of(2020, 5, 19, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 11, 55, 0)), + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 19, 13, 0, 0))); + + final List adjustedStatuses = converter.adjustStatuses(run, + LocalDate.of(2020, 5, 20).atStartOfDay(), + LocalDate.of(2020, 5, 21).atStartOfDay()); + + assertRunsActivityStats(adjustedStatuses, + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0))); + } + + @Test + public void testAdjustStatusesForPreviouslyStoppedRun() { + final PipelineRun run = run( + LocalDateTime.of(2020, 5, 19, 12, 0, 0), + LocalDateTime.of(2020, 5, 19, 13, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 11, 55, 0)), + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 19, 13, 0, 0))); + + final List adjustedStatuses = converter.adjustStatuses(run, + LocalDate.of(2020, 5, 20).atStartOfDay(), + LocalDate.of(2020, 5, 21).atStartOfDay()); + + assertRunsActivityStats(adjustedStatuses, + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); + } + + @Test + public void testAdjustStatusesForPreviouslyStartedPausedRun() { + final PipelineRun run = run( + LocalDateTime.of(2020, 5, 19, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 11, 55, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 19, 20, 0, 0))); final List adjustedStatuses = converter.adjustStatuses(run, @@ -429,11 +529,10 @@ public void testAdjustStatusesForPreviouslyStartedAndPreviouslyPausedRun() { } @Test - public void testAdjustStatusesForPreviouslyStartedAndPreviouslyPausedAndResumedRun() { + public void testAdjustStatusesForPreviouslyStartedPausedAndResumedRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 12, 0, 0)), + LocalDateTime.of(2020, 5, 19, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 11, 55, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 19, 20, 0, 0)), status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 14, 0, 0))); @@ -448,11 +547,10 @@ public void testAdjustStatusesForPreviouslyStartedAndPreviouslyPausedAndResumedR } @Test - public void testAdjustStatusesForPreviouslyStartedAndPreviouslyPausedAndPreviouslyResumedRun() { + public void testAdjustStatusesForPreviouslyStartedPausedResumedRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 12, 0, 0)), + LocalDateTime.of(2020, 5, 19, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 11, 55, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 19, 20, 0, 0)), status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 22, 0, 0))); @@ -466,11 +564,10 @@ public void testAdjustStatusesForPreviouslyStartedAndPreviouslyPausedAndPrevious } @Test - public void testAdjustStatusesForStartedAndIntermediatelyPausedAndIntermediatelyResumedRun() { + public void testAdjustStatusesForStartedAndIntermediatelyPausedResumedRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0)), status(TaskStatus.PAUSING, LocalDateTime.of(2020, 5, 20, 12, 55, 0)), status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 13, 0, 0)), status(TaskStatus.RESUMING, LocalDateTime.of(2020, 5, 20, 13, 55, 0)), @@ -490,25 +587,10 @@ public void testAdjustStatusesForStartedAndIntermediatelyPausedAndIntermediately } @Test - public void testAdjustStatusesForPreviouslyStoppedRun() { + public void testAdjustStatusesBoundsSyntheticFirstRunningStatusToRequestedInterval() { final PipelineRun run = run( - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 10, 0, 0)), - status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 19, 12, 0, 0))); - - final List adjustedStatuses = converter.adjustStatuses(run, - LocalDate.of(2020, 5, 20).atStartOfDay(), - LocalDate.of(2020, 5, 21).atStartOfDay()); - - assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); - } - - @Test - public void testAdjustStatusesUsesSyntheticFirstRunningStatusToRequestedInterval() { - final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 11, 55, 0), - NO_DATE, - status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 12, 0, 0))); + LocalDateTime.of(2020, 5, 19, 12, 0, 0), + status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 13, 0, 0))); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), @@ -516,33 +598,31 @@ public void testAdjustStatusesUsesSyntheticFirstRunningStatusToRequestedInterval assertRunsActivityStats(adjustedStatuses, status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 0, 0, 0)), - status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 13, 0, 0)), status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 21, 0, 0, 0))); } - + @Test - public void testAdjustStatusesUsesSyntheticFirstRunningStatusToRunStartTime() { + public void testAdjustStatusesBoundsSyntheticFirstRunningStatusToStartedDate() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 0, 0), - NO_DATE, - status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 12, 0, 0))); + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 13, 0, 0))); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), LocalDate.of(2020, 5, 21).atStartOfDay()); assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 0, 0)), - status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), + status(TaskStatus.PAUSED, LocalDateTime.of(2020, 5, 20, 13, 0, 0)), status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 21, 0, 0, 0))); } - + @Test - public void testAdjustStatusesUsesSyntheticLastStoppedStatusToRequestedInterval() { + public void testAdjustStatusesBoundsSyntheticLastStoppedStatusToRequestedInterval() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 11, 55, 0), - NO_DATE, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0))); + LocalDateTime.of(2020, 5, 20, 12, 0, 0), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0))); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), @@ -554,11 +634,11 @@ public void testAdjustStatusesUsesSyntheticLastStoppedStatusToRequestedInterval( } @Test - public void testAdjustStatusesUsesSyntheticLastStoppedStatusToRunEndTime() { + public void testAdjustStatusesBoundsSyntheticLastStoppedStatusToStoppedDate() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 11, 0, 0), + LocalDateTime.of(2020, 5, 20, 12, 0, 0), LocalDateTime.of(2020, 5, 20, 16, 0, 0), - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0))); + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 11, 55, 0))); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), @@ -570,24 +650,8 @@ public void testAdjustStatusesUsesSyntheticLastStoppedStatusToRunEndTime() { } @Test - public void testAdjustStatusesReturnsSingleStoppedStatusesForNotYetPreviouslyStoppedRuns() { - final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 10, 0, 0), - LocalDateTime.of(2020, 5, 19, 12, 0, 0), - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 19, 10, 0, 0)), - status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 19, 12, 0, 0))); - - final List adjustedStatuses = converter.adjustStatuses(run, - LocalDate.of(2020, 5, 20).atStartOfDay(), - LocalDate.of(2020, 5, 21).atStartOfDay()); - - assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); - } - - @Test - public void testAdjustStatusesUsesDefaultStatusesForRequestedInterval() { - final PipelineRun run = run(); + public void testAdjustStatusesForNoStatusesAndPreviouslyStartedRun() { + final PipelineRun run = run(LocalDateTime.of(2020, 5, 19, 0, 0)); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), @@ -599,10 +663,8 @@ public void testAdjustStatusesUsesDefaultStatusesForRequestedInterval() { } @Test - public void testAdjustStatusesUsesDefaultStatusesForRequestedIntervalConsideringRunStartDate() { - final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 12, 0, 0), - NO_DATE); + public void testAdjustStatusesForNoStatusesAndStartedDateRun() { + final PipelineRun run = run(LocalDateTime.of(2020, 5, 20, 12, 0, 0)); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), @@ -614,9 +676,9 @@ public void testAdjustStatusesUsesDefaultStatusesForRequestedIntervalConsidering } @Test - public void testAdjustStatusesUsesDefaultStatusesForRequestedIntervalConsideringRunEndDate() { + public void testAdjustStatusesForNoStatusesAndStartedStoppedDatesRun() { final PipelineRun run = run( - NO_DATE, + LocalDateTime.of(2020, 5, 20, 12, 0, 0), LocalDateTime.of(2020, 5, 20, 14, 0, 0)); final List adjustedStatuses = converter.adjustStatuses(run, @@ -624,30 +686,27 @@ public void testAdjustStatusesUsesDefaultStatusesForRequestedIntervalConsidering LocalDate.of(2020, 5, 21).atStartOfDay()); assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 0, 0, 0)), + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 14, 0, 0))); } @Test - public void testAdjustStatusesUsesDefaultStatusesForRequestedIntervalConsideringBothRunStartAndEndDate() { + public void testAdjustStatusesForNoStatusesAndAfterStartedDateRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 20, 12, 0, 0), - LocalDateTime.of(2020, 5, 20, 14, 0, 0)); + LocalDateTime.of(2020, 5, 21, 12, 0, 0)); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), LocalDate.of(2020, 5, 21).atStartOfDay()); assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 12, 0, 0)), - status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 14, 0, 0))); + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); } @Test - public void testAdjustStatusesUsesDefaultStatusesForAlreadyEndedRun() { + public void testAdjustStatusesForNoStatusesAndNoDatesRun() { final PipelineRun run = run( - NO_DATE, - LocalDateTime.of(2020, 5, 19, 14, 0, 0)); + NO_DATE); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), @@ -658,24 +717,23 @@ public void testAdjustStatusesUsesDefaultStatusesForAlreadyEndedRun() { } @Test - public void testAdjustStatusesUsesDefaultStatusesForNotYetStartedRun() { + public void testAdjustStatusesForNoStatusesAndPreviouslyStartedDateRun() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 21, 12, 0, 0), - NO_DATE); + LocalDateTime.of(2020, 5, 19, 12, 0, 0)); final List adjustedStatuses = converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), LocalDate.of(2020, 5, 21).atStartOfDay()); assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 20, 0, 0, 0))); + status(TaskStatus.RUNNING, LocalDateTime.of(2020, 5, 20, 0, 0, 0)), + status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 21, 0, 0, 0))); } @Test - public void testAdjustStatusesWorksWithoutSyncStartDate() { + public void testAdjustStatusesDoNotFailWithoutSyncStartDate() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 12, 0, 0), - NO_DATE); + LocalDateTime.of(2020, 5, 19, 12, 0, 0)); final List adjustedStatuses = converter.adjustStatuses(run, NO_DATE, @@ -687,31 +745,15 @@ public void testAdjustStatusesWorksWithoutSyncStartDate() { } @Test - public void testAdjustStatusesFailsWithoutSyncEndDate() { + public void testAdjustStatusesFailWithoutSyncEndDate() { final PipelineRun run = run( - LocalDateTime.of(2020, 5, 19, 12, 0, 0), - NO_DATE); + LocalDateTime.of(2020, 5, 19, 12, 0, 0)); assertThrows(IllegalArgumentException.class, () -> converter.adjustStatuses(run, LocalDate.of(2020, 5, 20).atStartOfDay(), NO_DATE)); } - @Test - public void testAdjustStatusesReturnsInfiniteIntervalForRunWithoutStartDate() { - final PipelineRun run = run( - NO_DATE, - NO_DATE); - - final List adjustedStatuses = converter.adjustStatuses(run, - NO_DATE, - LocalDate.of(2020, 5, 21).atStartOfDay()); - - assertRunsActivityStats(adjustedStatuses, - status(TaskStatus.RUNNING, LocalDateTime.MIN), - status(TaskStatus.STOPPED, LocalDateTime.of(2020, 5, 21, 0, 0, 0))); - } - private void assertRunsActivityStats(final List adjustedStatuses, final RunStatus... statuses) { assertThat(adjustedStatuses.size(), is(statuses.length)); for (int i = 0; i < statuses.length; i++) { @@ -720,28 +762,28 @@ private void assertRunsActivityStats(final List adjustedStatuses, fin } } - private PipelineRun run(final RunStatus... statuses) { + private PipelineRun run(final LocalDateTime start, final RunStatus... statuses) { + return run(start, NO_DATE, statuses); + } + + private PipelineRun run(final LocalDateTime start, final LocalDateTime end, final RunStatus... statuses) { final PipelineRun run = new PipelineRun(); - run.setStatus(TaskStatus.RUNNING); run.setId(RUN_ID); + run.setStatus(end == null ? TaskStatus.RUNNING : TaskStatus.STOPPED); run.setRunStatuses(Arrays.asList(statuses)); + run.setEndDate(toDate(end)); + run.setInstance(instance(start)); return run; } - private PipelineRun run(final LocalDateTime start, final LocalDateTime end, final RunStatus... statuses) { - final PipelineRun run = run(statuses); - run.setStatus(TaskStatus.STOPPED); - run.setStartDate(toDate(start)); - run.setEndDate(toDate(end)); - return run; + private RunInstance instance(final LocalDateTime start) { + final RunInstance instance = new RunInstance(); + instance.setStartDate(toDate(start)); + return instance; } private Date toDate(final LocalDateTime date) { - return Optional.ofNullable(date) - .map(it -> it.toInstant(ZoneOffset.UTC)) - .map(Instant::toEpochMilli) - .map(Date::new) - .orElse(null); + return Optional.ofNullable(date).map(DateUtils::convertLocalDateTimeToDate).orElse(null); } private NodeDisk disk(final long size, final LocalDateTime date) { diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java index 0bdf77f093..4d6fe5e3af 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java @@ -85,7 +85,7 @@ public class RunBillingMapperTest { private static final List TEST_GROUPS = Arrays.asList(TEST_GROUP_1, TEST_GROUP_2); private static final Date TEST_JAVA_DATE = DateUtils.now(); - private static final LocalDate TEST_DATE = DateUtils.toLocalDateTime(TEST_JAVA_DATE).toLocalDate(); + private static final LocalDate TEST_DATE = DateUtils.convertDateToLocalDateTime(TEST_JAVA_DATE).toLocalDate(); private static final Date TEST_STARTED_DATE = toDate(TEST_DATE.atStartOfDay()); private static final String TEST_STARTED_DATE_STR = toString(TEST_STARTED_DATE); private static final Date TEST_FINISHED_DATE = toDate(TEST_DATE.plusDays(1L).atStartOfDay()); diff --git a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java index ef20e35a99..11bf153797 100644 --- a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java +++ b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java @@ -41,13 +41,17 @@ public static LocalDateTime nowUTC() { return LocalDateTime.now(Clock.systemUTC()); } - public static LocalDateTime toLocalDateTime(final Date date) { - return date.toInstant().atZone(ZoneId.of("Z")).toLocalDateTime(); + public static LocalDateTime convertDateToLocalDateTime(final Date date) { + return date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime(); + } + + public static Date convertLocalDateTimeToDate(final LocalDateTime dateTime) { + return new Date(dateTime.toInstant(ZoneOffset.UTC).toEpochMilli()); } public static LocalDateTime parse(final DateFormat format, final String dateString) { try { - return toLocalDateTime(format.parse(dateString)); + return convertDateToLocalDateTime(format.parse(dateString)); } catch (ParseException e) { throw new IllegalArgumentException( String.format("Filed to parse date: %s with format: %s", dateString, format), e); From 8ca2ce76473b97d973b513fa7a36966f1d5502a1 Mon Sep 17 00:00:00 2001 From: Andrey Tsibin Date: Mon, 17 Apr 2023 12:11:07 +0300 Subject: [PATCH 4/6] Repair tests --- ...ClusterCostsMonitoringServiceCoreTest.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/api/src/test/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCoreTest.java b/api/src/test/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCoreTest.java index f075e687d2..b8c18309cc 100644 --- a/api/src/test/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCoreTest.java +++ b/api/src/test/java/com/epam/pipeline/manager/cluster/costs/ClusterCostsMonitoringServiceCoreTest.java @@ -16,6 +16,7 @@ package com.epam.pipeline.manager.cluster.costs; import com.epam.pipeline.entity.pipeline.PipelineRun; +import com.epam.pipeline.entity.pipeline.RunInstance; import com.epam.pipeline.entity.utils.DateUtils; import com.epam.pipeline.manager.pipeline.PipelineRunCRUDService; import com.epam.pipeline.manager.pipeline.PipelineRunManager; @@ -44,13 +45,13 @@ public class ClusterCostsMonitoringServiceCoreTest { private static final Long MASTER_ID_1 = 1L; - private static final Long WORKER_ID_11 = 2L; - private static final Long WORKER_ID_12 = 3L; - private static final Long MASTER_ID_2 = 4L; - private static final Long WORKER_ID_21 = 5L; + private static final Long WORKER_ID_11 = 11L; + private static final Long WORKER_ID_12 = 12L; + private static final Long WORKER_ID_13 = 13L; + private static final Long MASTER_ID_2 = 2L; + private static final Long WORKER_ID_21 = 21L; private static final double PRICE_1 = 1.95; private static final double PRICE_2 = 20.25; - private static final int WORKER_21_DURATION = 2; private static final double EXPECTED_PRICE_1 = 0.0975; private static final double EXPECTED_PRICE_2 = 0.675; @@ -65,18 +66,21 @@ public void shouldUpdateClusterPrices() { final PipelineRun master2 = masterRun(MASTER_ID_2, 1); when(pipelineRunManager.loadRunningPipelineRuns()).thenReturn(Arrays.asList(master1, master2)); - final PipelineRun worker11 = workerRun(WORKER_ID_11, MASTER_ID_1, PRICE_1); // not start time - final PipelineRun worker12 = workerRun(WORKER_ID_12, MASTER_ID_1, PRICE_1); // 3 min duration - worker12.setStartDate(buildDate(5)); - worker12.setEndDate(buildDate(2)); + final PipelineRun worker11 = workerRun(WORKER_ID_11, MASTER_ID_1, PRICE_1); // no start times + final PipelineRun worker12 = workerRun(WORKER_ID_12, MASTER_ID_1, PRICE_1); // no instance start time + final PipelineRun worker13 = workerRun(WORKER_ID_13, MASTER_ID_1, PRICE_1); // 3 min stopped + worker12.setStartDate(buildDate(10)); + worker13.setStartDate(buildDate(10)); + worker13.getInstance().setStartDate(buildDate(5)); + worker13.setEndDate(buildDate(2)); - // started 2 min ago and not completed - final PipelineRun worker21 = workerRun(WORKER_ID_21, MASTER_ID_2, PRICE_2); - worker21.setStartDate(buildDate(WORKER_21_DURATION)); + final PipelineRun worker21 = workerRun(WORKER_ID_21, MASTER_ID_2, PRICE_2); // 2 min running + worker21.setStartDate(buildDate(10)); + worker21.getInstance().setStartDate(buildDate(2)); when(pipelineRunCRUDService.loadRunsByParentRuns(any())).thenReturn(new HashMap>() { { - put(MASTER_ID_1, Arrays.asList(worker11, worker12)); + put(MASTER_ID_1, Arrays.asList(worker11, worker12, worker13)); put(MASTER_ID_2, Collections.singletonList(worker21)); } }); @@ -108,6 +112,7 @@ private PipelineRun workerRun(final Long id, final Long parentRunId, final doubl pipelineRun.setId(id); pipelineRun.setParentRunId(parentRunId); pipelineRun.setPricePerHour(BigDecimal.valueOf(price)); + pipelineRun.setInstance(new RunInstance()); return pipelineRun; } From cff42a7f81d67279c8a7201f9bedcb387835bf1e Mon Sep 17 00:00:00 2001 From: Andrey Tsibin Date: Mon, 17 Apr 2023 12:11:30 +0300 Subject: [PATCH 5/6] Resolve checkstyle and pmd issues --- .../manager/cluster/autoscale/AutoscalerServiceImpl.java | 1 - .../main/java/com/epam/pipeline/utils/RunDurationUtils.java | 5 ++++- .../impl/converter/RunToBillingRequestConverterImplTest.java | 1 - .../main/java/com/epam/pipeline/entity/utils/DateUtils.java | 1 - 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java index e98f8acb29..6a9e88bb3c 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscalerServiceImpl.java @@ -23,7 +23,6 @@ import com.epam.pipeline.entity.configuration.PipelineConfiguration; import com.epam.pipeline.entity.pipeline.PipelineRun; import com.epam.pipeline.entity.pipeline.RunInstance; -import com.epam.pipeline.entity.utils.DateUtils; import com.epam.pipeline.manager.cloud.CloudFacade; import com.epam.pipeline.manager.cluster.KubernetesConstants; import com.epam.pipeline.manager.cluster.NodeDiskManager; diff --git a/api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java b/api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java index 12100b8e20..1d38f9b3f5 100644 --- a/api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java +++ b/api/src/main/java/com/epam/pipeline/utils/RunDurationUtils.java @@ -7,7 +7,10 @@ import java.util.Date; import java.util.Optional; -public class RunDurationUtils { +public final class RunDurationUtils { + + private RunDurationUtils() { + } public static Duration getOverallDuration(final PipelineRun run) { return durationBetween(run.getStartDate(), run.getEndDate()); diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java index 78f762f95e..791bcfdd1a 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java @@ -37,7 +37,6 @@ import org.junit.jupiter.api.Test; import java.math.BigDecimal; -import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; diff --git a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java index 11bf153797..746d6957f0 100644 --- a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java +++ b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java @@ -20,7 +20,6 @@ import java.text.ParseException; import java.time.Clock; import java.time.LocalDateTime; -import java.time.ZoneId; import java.time.ZoneOffset; import java.util.Date; From 7d4969f0b2372619a3690f7698023005c9e8edc4 Mon Sep 17 00:00:00 2001 From: Andrey Tsibin Date: Mon, 17 Apr 2023 12:54:38 +0300 Subject: [PATCH 6/6] Move instance start date to run entity --- .../pipeline/dao/pipeline/PipelineRunDao.java | 25 +++++++++++++++---- .../cluster/autoscale/AutoscaleManager.java | 4 +-- .../cluster/autoscale/ReassignHandler.java | 2 +- .../manager/pipeline/PipelineRunManager.java | 5 ++++ .../main/resources/dao/pipeline-run-dao.xml | 19 ++++++++++---- .../dao/pipeline/PipelineRunDaoTest.java | 19 +++++++------- ...ClusterCostsMonitoringServiceCoreTest.java | 4 +-- .../com/epam/pipeline/util/TestUtils.java | 2 +- .../service/impl/TestUtils.java | 14 +++-------- .../RunToBillingRequestConverterImplTest.java | 14 +++-------- .../impl/mapper/RunBillingMapperTest.java | 2 +- .../pipeline/entity/pipeline/PipelineRun.java | 9 ++++--- .../pipeline/entity/pipeline/RunInstance.java | 2 -- .../pipeline/entity/pipeline/PipelineRun.java | 9 ++++--- .../pipeline/entity/pipeline/RunInstance.java | 2 -- .../epam/pipeline/entity/utils/DateUtils.java | 4 +++ 16 files changed, 76 insertions(+), 60 deletions(-) diff --git a/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java b/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java index 0f3c73e34f..c7e669e211 100644 --- a/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java +++ b/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java @@ -33,6 +33,7 @@ import com.epam.pipeline.entity.pipeline.run.parameter.RunSid; import com.epam.pipeline.entity.region.CloudProvider; import com.epam.pipeline.entity.user.PipelineUser; +import com.epam.pipeline.entity.utils.DateUtils; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections4.ListUtils; @@ -109,6 +110,7 @@ public class PipelineRunDao extends NamedParameterJdbcDaoSupport { private String countFilteredPipelineRunsBaseQuery; private String loadPipelineRunsWithPipelineByIdsQuery; private String updateRunInstanceQuery; + private String updateRunInstanceStartDateQuery; private String updatePodIPQuery; private String loadRunsGroupingQuery; private String loadRunsCountGroupingQuery; @@ -267,6 +269,14 @@ public void updateRunInstance(PipelineRun run) { .getParameters(run, getConnection())); } + @Transactional(propagation = Propagation.MANDATORY) + public void updateRunInstanceStartDate(final Long id, final LocalDateTime date) { + MapSqlParameterSource params = new MapSqlParameterSource(); + params.addValue(PipelineRunParameters.RUN_ID.name(), id); + params.addValue(PipelineRunParameters.NODE_START_DATE.name(), DateUtils.convertLocalDateTimeToDate(date)); + getNamedParameterJdbcTemplate().update(updateRunInstanceStartDateQuery, params); + } + @Transactional(propagation = Propagation.REQUIRED) public void updatePodIP(PipelineRun run) { getNamedParameterJdbcTemplate().update(updatePodIPQuery, PipelineRunParameters @@ -847,6 +857,7 @@ static MapSqlParameterSource getParameters(PipelineRun run, Connection connectio params.addValue(PIPELINE_ID.name(), run.getPipelineId()); params.addValue(VERSION.name(), run.getVersion()); params.addValue(START_DATE.name(), run.getStartDate()); + params.addValue(NODE_START_DATE.name(), run.getInstanceStartDate()); params.addValue(END_DATE.name(), run.getEndDate()); params.addValue(PARAMETERS.name(), run.getParams()); params.addValue(STATUS.name(), run.getStatus().getId()); @@ -904,7 +915,6 @@ private static void addInstanceFields(PipelineRun run, MapSqlParameterSource par instance.map(RunInstance::getCloudProvider).map(CloudProvider::name).orElse(null)); params.addValue(NODE_PLATFORM.name(), instance.map(RunInstance::getNodePlatform).orElse(null)); params.addValue(NODE_POOL_ID.name(), instance.map(RunInstance::getPoolId).orElse(null)); - params.addValue(NODE_START_DATE.name(), instance.map(RunInstance::getStartDate).orElse(null)); } static ResultSetExtractor> getRunGroupExtractor() { @@ -950,6 +960,10 @@ public static PipelineRun parsePipelineRun(ResultSet rs) throws SQLException { run.setPipelineName(rs.getString(PIPELINE_NAME.name())); run.setVersion(rs.getString(VERSION.name())); run.setStartDate(new Date(rs.getTimestamp(START_DATE.name()).getTime())); + Timestamp instanceStartDate = rs.getTimestamp(NODE_START_DATE.name()); + if (!rs.wasNull()) { + run.setInstanceStartDate(new Date(instanceStartDate.getTime())); + } run.setParams(rs.getString(PARAMETERS.name())); run.setStatus(TaskStatus.getById(rs.getLong(STATUS.name()))); run.setCommitStatus(CommitStatus.getById(rs.getLong(COMMIT_STATUS.name()))); @@ -987,10 +1001,6 @@ public static PipelineRun parsePipelineRun(ResultSet rs) throws SQLException { instance.setCloudProvider(CloudProvider.valueOf(rs.getString(NODE_CLOUD_PROVIDER.name()))); instance.setNodePlatform(rs.getString(NODE_PLATFORM.name())); instance.setPoolId(rs.getLong(NODE_POOL_ID.name())); - Timestamp instanceStart = rs.getTimestamp(NODE_START_DATE.name()); - if (!rs.wasNull()) { - instance.setStartDate(new Date(instanceStart.getTime())); - } boolean spot = rs.getBoolean(IS_SPOT.name()); if (!rs.wasNull()) { @@ -1248,6 +1258,11 @@ public void setUpdateRunInstanceQuery(String updateRunInstanceQuery) { this.updateRunInstanceQuery = updateRunInstanceQuery; } + @Required + public void setUpdateRunInstanceStartDateQuery(String updateRunInstanceStartDateQuery) { + this.updateRunInstanceStartDateQuery = updateRunInstanceStartDateQuery; + } + @Required public void setUpdatePodIPQuery(String updatePodIPQuery) { this.updatePodIPQuery = updatePodIPQuery; diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java index 723bd90cdc..db97cd373c 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/AutoscaleManager.java @@ -491,9 +491,9 @@ private void createNodeForRun(List> tasks, String runId, pipelineRunManager.updateRunInstance(longId, requiredInstance.getInstance()); RunInstance instance = cloudFacade .scaleUpNode(longId, requiredInstance.getInstance(), requiredInstance.getRuntimeParameters()); - instance.setStartDate(DateUtils.now()); - //save actual instance + //save instance ID and IP pipelineRunManager.updateRunInstance(longId, instance); + pipelineRunManager.updateRunInstanceStartDate(longId, DateUtils.nowUTC()); autoscalerService.registerDisks(longId, instance); Instant end = Instant.now(); removeNodeUpTask(longId); diff --git a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java index 2b24ea9fcb..8d8c0c7ee7 100644 --- a/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java +++ b/api/src/main/java/com/epam/pipeline/manager/cluster/autoscale/ReassignHandler.java @@ -184,8 +184,8 @@ private boolean reassignInstance(final String newNodeId, final RunInstance reassignedInstance = StringUtils.isBlank(instance.getNodeId()) ? cloudFacade.describeInstance(runId, instance) : instance; reassignedInstance.setPoolId(instance.getPoolId()); - reassignedInstance.setStartDate(DateUtils.now()); pipelineRunManager.updateRunInstance(runId, reassignedInstance); + pipelineRunManager.updateRunInstanceStartDate(runId, DateUtils.nowUTC()); final List disks = cloudFacade.loadDisks(reassignedInstance.getCloudRegionId(), runId); autoscalerService.adjustRunPrices(runId, disks); diff --git a/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java b/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java index 1f1dbea0fb..26751d3604 100644 --- a/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java +++ b/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java @@ -627,6 +627,11 @@ public PipelineRun updateRunInstance(Long id, RunInstance instance) { return pipelineRun; } + @Transactional(propagation = Propagation.REQUIRED) + public void updateRunInstanceStartDate(Long id, LocalDateTime date) { + pipelineRunDao.updateRunInstanceStartDate(id, date); + } + @Transactional(propagation = Propagation.REQUIRED) public PipelineRun updatePipelineStatusIfNotFinalExternal(Long runId, TaskStatus status) { return updatePipelineStatusIfNotFinal(runId, status); diff --git a/api/src/main/resources/dao/pipeline-run-dao.xml b/api/src/main/resources/dao/pipeline-run-dao.xml index 91a7d0e1f3..60540fd9c4 100644 --- a/api/src/main/resources/dao/pipeline-run-dao.xml +++ b/api/src/main/resources/dao/pipeline-run-dao.xml @@ -454,11 +454,20 @@ node_id = :NODE_ID, node_disk = :NODE_DISK, node_ip = :NODE_IP, - node_image =:NODE_IMAGE, - node_name =:NODE_NAME, - is_spot =:IS_SPOT, - node_real_disk =:NODE_REAL_DISK, - node_pool_id = :NODE_POOL_ID, + node_image = :NODE_IMAGE, + node_name = :NODE_NAME, + is_spot = :IS_SPOT, + node_real_disk = :NODE_REAL_DISK, + node_pool_id = :NODE_POOL_ID + WHERE + run_id = :RUN_ID + ]]> + + + + + >() { { diff --git a/api/src/test/java/com/epam/pipeline/util/TestUtils.java b/api/src/test/java/com/epam/pipeline/util/TestUtils.java index 4b6f621f61..5a8cf12314 100644 --- a/api/src/test/java/com/epam/pipeline/util/TestUtils.java +++ b/api/src/test/java/com/epam/pipeline/util/TestUtils.java @@ -141,6 +141,7 @@ public static PipelineRun createPipelineRun(Long pipelineId, String params, Task PipelineRun run = new PipelineRun(); run.setPipelineId(pipelineId); run.setStartDate(new Date()); + run.setInstanceStartDate(new Date()); run.setEndDate(new Date()); run.setStatus(status); run.setCommitStatus(CommitStatus.NOT_COMMITTED); @@ -158,7 +159,6 @@ public static PipelineRun createPipelineRun(Long pipelineId, String params, Task instance.setSpot(isSpot); instance.setNodeId("1"); instance.setNodePlatform(TEST_PLATFORM); - instance.setStartDate(new Date()); run.setInstance(instance); run.setEntitiesIds(Collections.singletonList(entitiesId)); run.setConfigurationId(configurationId); diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java index 906bebca61..2d8e837219 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/TestUtils.java @@ -22,7 +22,6 @@ import com.epam.pipeline.entity.pipeline.TaskStatus; import com.epam.pipeline.entity.region.AbstractCloudRegion; import com.epam.pipeline.entity.region.AwsRegion; -import com.epam.pipeline.entity.utils.DateUtils; import com.fasterxml.jackson.core.JsonFactory; import org.apache.commons.collections.CollectionUtils; import org.elasticsearch.common.Strings; @@ -37,7 +36,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Map; -import java.util.Optional; public final class TestUtils { @@ -70,7 +68,8 @@ public static Map getPuttedObject(final XContentBuilder contentB } public static PipelineRun createTestPipelineRun(final Long runId, final Long pipelineId, final String tool, - final BigDecimal price, final RunInstance instance) { + final BigDecimal price, final LocalDateTime date, + final RunInstance instance) { final PipelineRun run = new PipelineRun(); run.setId(runId); run.setPipelineId(pipelineId); @@ -78,22 +77,17 @@ public static PipelineRun createTestPipelineRun(final Long runId, final Long pip run.setPricePerHour(price); run.setInstance(instance); run.setStatus(TaskStatus.RUNNING); + run.setInstanceStartDateTime(date); return run; } - public static RunInstance createTestInstance(final Long regionId, final String nodeType, - final LocalDateTime date) { + public static RunInstance createTestInstance(final Long regionId, final String nodeType) { final RunInstance instance = new RunInstance(); instance.setCloudRegionId(regionId); instance.setNodeType(nodeType); - instance.setStartDate(Optional.ofNullable(date).map(DateUtils::convertLocalDateTimeToDate).orElse(null)); return instance; } - public static RunInstance createTestInstance(final Long regionId, final String nodeType) { - return createTestInstance(regionId, nodeType, null); - } - public static AbstractCloudRegion createTestRegion(final Long regionId) { final AwsRegion region = new AwsRegion(); region.setId(regionId); diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java index 791bcfdd1a..e8c9eb81d5 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/converter/RunToBillingRequestConverterImplTest.java @@ -27,7 +27,6 @@ import com.epam.pipeline.billingreportagent.service.impl.mapper.RunBillingMapper; import com.epam.pipeline.entity.cluster.NodeDisk; import com.epam.pipeline.entity.pipeline.PipelineRun; -import com.epam.pipeline.entity.pipeline.RunInstance; import com.epam.pipeline.entity.pipeline.TaskStatus; import com.epam.pipeline.entity.pipeline.run.RunStatus; import com.epam.pipeline.entity.user.PipelineUser; @@ -91,9 +90,8 @@ public void convertShouldReturnElasticRequests() { final LocalDateTime prevSync = LocalDate.of(2019, 12, 4).atStartOfDay(); final LocalDateTime syncStart = LocalDate.of(2019, 12, 5).atStartOfDay(); - final PipelineRun run = TestUtils.createTestPipelineRun(RUN_ID, PIPELINE_ID, TOOL_IMAGE, PRICE, - TestUtils.createTestInstance(REGION_ID, NODE_TYPE, - prevSync)); + final PipelineRun run = TestUtils.createTestPipelineRun(RUN_ID, PIPELINE_ID, TOOL_IMAGE, PRICE, prevSync, + TestUtils.createTestInstance(REGION_ID, NODE_TYPE)); final EntityContainer runContainer = EntityContainer.builder() @@ -770,17 +768,11 @@ private PipelineRun run(final LocalDateTime start, final LocalDateTime end, fina run.setId(RUN_ID); run.setStatus(end == null ? TaskStatus.RUNNING : TaskStatus.STOPPED); run.setRunStatuses(Arrays.asList(statuses)); + run.setInstanceStartDate(toDate(start)); run.setEndDate(toDate(end)); - run.setInstance(instance(start)); return run; } - private RunInstance instance(final LocalDateTime start) { - final RunInstance instance = new RunInstance(); - instance.setStartDate(toDate(start)); - return instance; - } - private Date toDate(final LocalDateTime date) { return Optional.ofNullable(date).map(DateUtils::convertLocalDateTimeToDate).orElse(null); } diff --git a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java index 4d6fe5e3af..548507cdd9 100644 --- a/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java +++ b/billing-report-agent/src/test/java/com/epam/pipeline/billingreportagent/service/impl/mapper/RunBillingMapperTest.java @@ -115,7 +115,7 @@ private static String toString(final Date date) { public void testRunMapperMap() throws IOException { final PipelineRun run = TestUtils.createTestPipelineRun(TEST_RUN_ID, TEST_PIPELINE_ID, TEST_TOOL_IMAGE, TEST_PRICE, - TestUtils.createTestInstance(TEST_REGION_ID, TEST_NODE_TYPE)); + DateUtils.nowUTC(), TestUtils.createTestInstance(TEST_REGION_ID, TEST_NODE_TYPE)); run.setPipelineId(TEST_PIPELINE_ID); run.setPipelineName(TEST_PIPELINE_NAME); run.setVersion(TEST_PIPELINE_VERSION); diff --git a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java index 5ade756f4c..127e2351de 100644 --- a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java +++ b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java @@ -55,6 +55,7 @@ public class PipelineRun extends AbstractSecuredEntity { private Long pipelineId; private Date startDate; + private Date instanceStartDate; private String version; private Date endDate; private TaskStatus status; @@ -191,12 +192,12 @@ public String getTaskName() { } @JsonIgnore - public Date getInstanceStartDate() { - return Optional.ofNullable(instance).map(RunInstance::getStartDate).orElse(null); + public LocalDateTime getInstanceStartDateTime() { + return Optional.ofNullable(getInstanceStartDate()).map(DateUtils::convertDateToLocalDateTime).orElse(null); } @JsonIgnore - public LocalDateTime getInstanceStartDateTime() { - return Optional.ofNullable(getInstanceStartDate()).map(DateUtils::convertDateToLocalDateTime).orElse(null); + public void setInstanceStartDateTime(final LocalDateTime date) { + instanceStartDate = Optional.ofNullable(date).map(DateUtils::convertLocalDateTimeToDate).orElse(null); } } diff --git a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java index 5e27d5215d..222f8541f5 100644 --- a/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java +++ b/cloud-pipeline-common/model/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java @@ -19,7 +19,6 @@ import com.epam.pipeline.entity.region.CloudProvider; import com.fasterxml.jackson.annotation.JsonIgnore; -import java.util.Date; import java.util.Objects; import java.util.Set; @@ -60,7 +59,6 @@ public class RunInstance { */ private Set prePulledDockerImages; private Long poolId; - private Date startDate; @JsonIgnore public boolean isEmpty() { diff --git a/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java b/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java index 0a04d347eb..8d80f8be22 100644 --- a/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java +++ b/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java @@ -57,6 +57,7 @@ public class PipelineRun extends AbstractSecuredEntity { private Long pipelineId; private Date startDate; + private Date instanceStartDate; private String version; private Date endDate; private TaskStatus status; @@ -256,12 +257,12 @@ public void removeTag(final String key) { } @JsonIgnore - public Date getInstanceStartDate() { - return Optional.ofNullable(instance).map(RunInstance::getStartDate).orElse(null); + public LocalDateTime getInstanceStartDateTime() { + return Optional.ofNullable(instanceStartDate).map(DateUtils::convertDateToLocalDateTime).orElse(null); } @JsonIgnore - public LocalDateTime getInstanceStartDateTime() { - return Optional.ofNullable(getInstanceStartDate()).map(DateUtils::convertDateToLocalDateTime).orElse(null); + public void setInstanceStartDateTime(final LocalDateTime date) { + instanceStartDate = Optional.ofNullable(date).map(DateUtils::convertLocalDateTimeToDate).orElse(null); } } diff --git a/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java b/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java index b3a5c984ce..15aa0d7ed5 100644 --- a/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java +++ b/core/src/main/java/com/epam/pipeline/entity/pipeline/RunInstance.java @@ -25,7 +25,6 @@ import lombok.ToString; import org.springframework.util.StringUtils; -import java.util.Date; import java.util.Objects; import java.util.Set; @@ -61,7 +60,6 @@ public class RunInstance { */ private Set prePulledDockerImages; private Long poolId; - private Date startDate; public RunInstance(final String nodeType, final Integer nodeDisk, diff --git a/core/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java b/core/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java index bac393059f..7a248cf7d1 100644 --- a/core/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java +++ b/core/src/main/java/com/epam/pipeline/entity/utils/DateUtils.java @@ -55,6 +55,10 @@ public static LocalDateTime convertDateToLocalDateTime(final Date date) { return date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime(); } + public static Date convertLocalDateTimeToDate(final LocalDateTime dateTime) { + return new Date(dateTime.toInstant(ZoneOffset.UTC).toEpochMilli()); + } + public static LocalDateTime convertEpochMillisToLocalDateTime(final long epochMillis) { return Instant.ofEpochMilli(epochMillis).atZone(ZoneOffset.UTC).toLocalDateTime(); }