Merge pull request #516 from bsinno/fix_remove_report_mgmt
Remove unused report management.
This commit is contained in:
@@ -1,211 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.report.model.DataReportSeries;
|
||||
import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries;
|
||||
import org.eclipse.hawkbit.repository.report.model.ListReportSeries;
|
||||
import org.eclipse.hawkbit.repository.report.model.SeriesTime;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
/**
|
||||
* Service layer for generating hawkBit statistics and reports.
|
||||
*
|
||||
*/
|
||||
public interface ReportManagement {
|
||||
|
||||
/**
|
||||
* Data base format.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface DateType<T> {
|
||||
/**
|
||||
* @param s
|
||||
* @return T
|
||||
*/
|
||||
T format(String s);
|
||||
|
||||
/**
|
||||
* h2 format.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String h2Format();
|
||||
|
||||
/**
|
||||
* mysql format.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String mySqlFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DateTypes.
|
||||
*/
|
||||
public static final class DateTypes implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final PerMonth PER_MONTH = new PerMonth();
|
||||
|
||||
private DateTypes() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PerMonth
|
||||
*/
|
||||
public static PerMonth perMonth() {
|
||||
return PER_MONTH;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the date format based on DB H2 or mySql.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static final class PerMonth implements DateType<LocalDate>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String DATE_PATTERN = "yyyy-MM";
|
||||
|
||||
@Override
|
||||
public LocalDate format(final String s) {
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
|
||||
final YearMonth ym = YearMonth.parse(s, formatter);
|
||||
return ym.atDay(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String h2Format() {
|
||||
return DATE_PATTERN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mySqlFormat() {
|
||||
return "%Y-%m";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report of the top x distribution set assigned usage as a list
|
||||
* of {@link InnerOuterDataReportSeries} which is ideal for generate a donut
|
||||
* chart out of it. The inner series contains the distribution set names and
|
||||
* total count usage. The outer series contains each version usage and its
|
||||
* usage count. {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2}
|
||||
* {@code inner: ds2:1 -> outer: vers 0.0.1:1}
|
||||
*
|
||||
* The top x entries are seperated within the series, the rest of the
|
||||
* distribution sets usage are summarized to a "misc" series.
|
||||
*
|
||||
* @param topXEntries
|
||||
* the top entries which should be shown, the rest distribution
|
||||
* set entries are summarized as "misc"
|
||||
* @return a list of inner and outer series of distribution set usage
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
List<InnerOuterDataReportSeries<String>> distributionUsageAssigned(int topXEntries);
|
||||
|
||||
/**
|
||||
* Generates a report of the top x distribution set installed usage as a
|
||||
* list of {@link InnerOuterDataReportSeries} which is ideal for generate a
|
||||
* donut chart out of it. The inner series contains the distribution set
|
||||
* names and total count usage. The outer series contains each version usage
|
||||
* and its usage count.
|
||||
* {@code inner: ds1:5 -> outer: vers 0.0.0:3, vers 1.0.0:2}
|
||||
* {@code inner: ds2:1 -> outer: vers 0.0.1:1}
|
||||
*
|
||||
* The top x entries are seperated within the series, the rest of the
|
||||
* distribution sets usage are summarized to a "misc" series.
|
||||
*
|
||||
* @param topXEntries
|
||||
* the top entries which should be shown, the rest distribution
|
||||
* set entries are summarized as "misc"
|
||||
* @return a list of inner and outer series of distribution set usage
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
List<InnerOuterDataReportSeries<String>> distributionUsageInstalled(int topXEntries);
|
||||
|
||||
/**
|
||||
* Generates report for feedback over period.
|
||||
*
|
||||
* @param dateType
|
||||
* {@link PerMonth}
|
||||
* @param from
|
||||
* start date
|
||||
* @param to
|
||||
* end date
|
||||
* @return <T> DataReportSeries<T> ListReportSeries list of action status
|
||||
* count
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
<T extends Serializable> DataReportSeries<T> feedbackReceivedOverTime(@NotNull DateType<T> dateType,
|
||||
@NotNull LocalDateTime from, @NotNull LocalDateTime to);
|
||||
|
||||
/**
|
||||
* Generates report for target created over period.
|
||||
*
|
||||
* @param dateType
|
||||
* {@link PerMonth}
|
||||
* @param from
|
||||
* start date
|
||||
* @param to
|
||||
* end date
|
||||
* @return <T> DataReportSeries<T> ListReportSeries list of target created
|
||||
* count
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
<T extends Serializable> DataReportSeries<T> targetsCreatedOverPeriod(@NotNull DateType<T> dateType,
|
||||
@NotNull LocalDateTime from, @NotNull LocalDateTime to);
|
||||
|
||||
/**
|
||||
* Generates a report as a {@link ListReportSeries} targets polled based on
|
||||
* the {@link Target#getLastTargetQuery()} within an hour, day, week, month,
|
||||
* year, more than a year, never.
|
||||
*
|
||||
* The order of the numbers within the {@link DataReportSeries} is the order
|
||||
* hour, day, week, month, year, more than a year, never.
|
||||
*
|
||||
* @return a {@link DataReportSeries} which contains the number of targets
|
||||
* which have not been polled in the last hour, day, ... year,more
|
||||
* than a year, never.
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
DataReportSeries<SeriesTime> targetsLastPoll();
|
||||
|
||||
/**
|
||||
* Generates a report of all targets of their current update status count.
|
||||
* For each {@link TargetUpdateStatus} an total count of targets which are
|
||||
* in this status currently.
|
||||
*
|
||||
* @return a data report series which contains the target count for each
|
||||
* target update status
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
DataReportSeries<TargetUpdateStatus> targetStatus();
|
||||
|
||||
}
|
||||
@@ -1,421 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ReportManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.report.model.DataReportSeries;
|
||||
import org.eclipse.hawkbit.repository.report.model.DataReportSeriesItem;
|
||||
import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries;
|
||||
import org.eclipse.hawkbit.repository.report.model.SeriesTime;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link ReportManagement}.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class JpaReportManagement implements ReportManagement {
|
||||
|
||||
@Value("${spring.jpa.database}")
|
||||
private String databaseType;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
|
||||
private static final String H2_TARGET_CREATED_SQL_TEMPLATE = "SELECT TO_CHAR( DATEADD('second', target0_.created_at / 1000, DATE '1970-01-01'), '%s') AS col_0_0_, count(target0_.controller_id) AS col_1_0_ from sp_target target0_ WHERE TO_CHAR(DATEADD('second', target0_.created_at / 1000, DATE '1970-01-01'),'%s') BETWEEN TO_CHAR('%s', '%s') and TO_CHAR('%s', '%s') AND UPPER(target0_.tenant)=UPPER('%s') GROUP BY TO_CHAR(DATEADD('second', target0_.created_at / 1000, DATE '1970-01-01'), '%s')";
|
||||
|
||||
private static final String H2_CONTROLLER_FRRDBACK_SQL_TEMPLATE = "SELECT TO_CHAR(DATEADD('second', action_.created_at / 1000, DATE '1970-01-01'), '%s') AS col_0_0_, count(action_.id) AS col_1_0_ FROM sp_action action_ WHERE TO_CHAR(DATEADD('second', action_.created_at / 1000, DATE '1970-01-01'), '%s') BETWEEN TO_CHAR('%s', '%s') AND TO_CHAR('%s', '%s') AND UPPER(action_.tenant)=UPPER('%s') GROUP BY TO_CHAR(DATEADD('second', action_.created_at / 1000, DATE '1970-01-01'), '%s')";
|
||||
|
||||
private static final String MYSQL_TARGET_CREATED_SQL_TEMPLATE = "SELECT DATE_FORMAT(FROM_UNIXTIME(target0_.created_at / 1000), '%s') AS col_0_0_, COUNT(target0_.controller_id) AS col_1_0_ FROM sp_target target0_ WHERE DATE_FORMAT(FROM_UNIXTIME(target0_.created_at / 1000),'%s') BETWEEN DATE_FORMAT('%s', '%s') AND DATE_FORMAT('%s', '%s') AND UPPER(target0_.tenant)=UPPER('%s') GROUP BY DATE_FORMAT(FROM_UNIXTIME(target0_.created_at / 1000), '%s')";
|
||||
|
||||
private static final String MYSQL_CONTROLLER_FRRDBACK_SQL_TEMPLATE = "SELECT DATE_FORMAT(FROM_UNIXTIME(action_.created_at / 1000), '%s') AS col_0_0_, COUNT(action_.id) as col_1_0_ FROM sp_action action_ WHERE DATE_FORMAT(FROM_UNIXTIME(action_.created_at / 1000),'%s') BETWEEN DATE_FORMAT('%s', '%s') AND DATE_FORMAT('%s', '%s') AND UPPER(action_.tenant)=UPPER('%s') GROUP BY DATE_FORMAT(FROM_UNIXTIME(action_.created_at / 1000), '%s')";
|
||||
|
||||
private static final String MYSQL_DB_TYPE = "MYSQL";
|
||||
|
||||
private static final String H2_DB_TYPE = "H2";
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
|
||||
@Override
|
||||
public DataReportSeries<TargetUpdateStatus> targetStatus() {
|
||||
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
|
||||
final Root<JpaTarget> targetRoot = query.from(JpaTarget.class);
|
||||
final Expression<Long> countColumn = cb.count(targetRoot.get(JpaTarget_.id));
|
||||
final CriteriaQuery<Object[]> multiselect = query
|
||||
.multiselect(targetRoot.get(JpaTarget_.updateStatus), countColumn)
|
||||
.groupBy(targetRoot.get(JpaTarget_.updateStatus))
|
||||
.orderBy(cb.desc(targetRoot.get(JpaTarget_.updateStatus)));
|
||||
|
||||
// | col1 | col2 |
|
||||
// | U_STATUS | COUNT |
|
||||
final List<Object[]> resultList = entityManager.createQuery(multiselect).getResultList();
|
||||
|
||||
final List<DataReportSeriesItem<TargetUpdateStatus>> reportSeriesItems = resultList.stream()
|
||||
.map(r -> new DataReportSeriesItem<>((TargetUpdateStatus) r[0], (Long) r[1]))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new DataReportSeries<>("Target Status Overview", reportSeriesItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataReportSeries<SeriesTime> targetsLastPoll() {
|
||||
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
final LocalDateTime beforeHour = now.minusHours(1);
|
||||
final LocalDateTime beforeDay = now.minusDays(1);
|
||||
final LocalDateTime beforeWeek = now.minusWeeks(1);
|
||||
final LocalDateTime beforeMonth = now.minusMonths(1);
|
||||
final LocalDateTime beforeYear = now.minusYears(1);
|
||||
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final List<DataReportSeriesItem<SeriesTime>> resultList = new ArrayList<>();
|
||||
|
||||
// hours
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.HOUR,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, beforeHour, now)).getSingleResult()));
|
||||
// days
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.DAY, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeDay, beforeHour)).getSingleResult()));
|
||||
// weeks
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.WEEK, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeWeek, beforeDay)).getSingleResult()));
|
||||
// months
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.MONTH, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeMonth, beforeWeek)).getSingleResult()));
|
||||
// years
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.YEAR, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeYear, beforeMonth)).getSingleResult()));
|
||||
// years
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.MORE_THAN_YEAR,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, beforeYear)).getSingleResult()));
|
||||
// never
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.NEVER,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, null)).getSingleResult()));
|
||||
|
||||
return new DataReportSeries<>("TargetLastPoll", resultList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InnerOuterDataReportSeries<String>> distributionUsageAssigned(final int topXEntries) {
|
||||
|
||||
// top X entries distribution usage
|
||||
final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> queryTopX = cbTopX.createQuery(Object[].class);
|
||||
final Root<JpaDistributionSet> rootTopX = queryTopX.from(JpaDistributionSet.class);
|
||||
final ListJoin<JpaDistributionSet, JpaTarget> joinTopX = rootTopX.join(JpaDistributionSet_.assignedToTargets,
|
||||
JoinType.LEFT);
|
||||
final Expression<Long> countColumn = cbTopX.count(joinTopX);
|
||||
// top x usage query
|
||||
final CriteriaQuery<Object[]> groupBy = queryTopX
|
||||
.multiselect(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version),
|
||||
countColumn)
|
||||
.where(cbTopX.equal(rootTopX.get(JpaDistributionSet_.deleted), false))
|
||||
.groupBy(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version))
|
||||
.orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(JpaDistributionSet_.name)));
|
||||
// | col1 | col2 | col3 |
|
||||
// | NAME | VER | COUNT |
|
||||
final List<Object[]> resultListTop = entityManager.createQuery(groupBy).getResultList();
|
||||
// end of top X entries distribution usage
|
||||
|
||||
return mapDistirbutionUsageResultToDataReport(topXEntries, resultListTop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InnerOuterDataReportSeries<String>> distributionUsageInstalled(final int topXEntries) {
|
||||
// top X entries distribution usage
|
||||
final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> queryTopX = cbTopX.createQuery(Object[].class);
|
||||
final Root<JpaDistributionSet> rootTopX = queryTopX.from(JpaDistributionSet.class);
|
||||
final ListJoin<JpaDistributionSet, JpaTarget> joinTopX = rootTopX.join(JpaDistributionSet_.installedAtTargets,
|
||||
JoinType.LEFT);
|
||||
final Expression<Long> countColumn = cbTopX.count(joinTopX);
|
||||
// top x usage query
|
||||
final CriteriaQuery<Object[]> groupBy = queryTopX
|
||||
.multiselect(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version),
|
||||
countColumn)
|
||||
.where(cbTopX.equal(rootTopX.get(JpaDistributionSet_.deleted), false))
|
||||
.groupBy(rootTopX.get(JpaDistributionSet_.name), rootTopX.get(JpaDistributionSet_.version))
|
||||
.orderBy(cbTopX.desc(countColumn), cbTopX.asc(rootTopX.get(JpaDistributionSet_.name)));
|
||||
// | col1 | col2 | col3 |
|
||||
// | NAME | VER | COUNT |
|
||||
final List<Object[]> resultListTop = entityManager.createQuery(groupBy).getResultList();
|
||||
// end of top X entries distribution usage
|
||||
|
||||
return mapDistirbutionUsageResultToDataReport(topXEntries, resultListTop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Serializable> DataReportSeries<T> targetsCreatedOverPeriod(final DateType<T> dateType,
|
||||
final LocalDateTime from, final LocalDateTime to) {
|
||||
final Query createNativeQuery = entityManager
|
||||
.createNativeQuery(getTargetsCreatedQueryTemplate(dateType, from, to));
|
||||
final List<Object[]> resultList = createNativeQuery.getResultList();
|
||||
|
||||
final List<DataReportSeriesItem<T>> reportItems = resultList.stream()
|
||||
.map(r -> new DataReportSeriesItem<>(dateType.format((String) r[0]), ((Number) r[1]).longValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new DataReportSeries<>("CreatedTargets", reportItems);
|
||||
}
|
||||
|
||||
private String getTargetsCreatedQueryTemplate(final DateType<?> dateType, final LocalDateTime from,
|
||||
final LocalDateTime to) {
|
||||
switch (databaseType) {
|
||||
case H2_DB_TYPE:
|
||||
return String.format(H2_TARGET_CREATED_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType),
|
||||
to.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
case MYSQL_DB_TYPE:
|
||||
return String.format(MYSQL_TARGET_CREATED_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.toString(), dateTimeFormatToSqlFormat(dateType),
|
||||
to.toString(), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getFeedbackReceivedQueryTemplate(final DateType<?> dateType, final LocalDateTime from,
|
||||
final LocalDateTime to) {
|
||||
switch (databaseType) {
|
||||
case H2_DB_TYPE:
|
||||
return String.format(H2_CONTROLLER_FRRDBACK_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType),
|
||||
to.format(DATE_FORMAT), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
case MYSQL_DB_TYPE:
|
||||
return String.format(MYSQL_CONTROLLER_FRRDBACK_SQL_TEMPLATE, dateTimeFormatToSqlFormat(dateType),
|
||||
dateTimeFormatToSqlFormat(dateType), from.toString(), dateTimeFormatToSqlFormat(dateType),
|
||||
to.toString(), dateTimeFormatToSqlFormat(dateType), tenantAware.getCurrentTenant(),
|
||||
dateTimeFormatToSqlFormat(dateType));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Serializable> DataReportSeries<T> feedbackReceivedOverTime(final DateType<T> dateType,
|
||||
final LocalDateTime from, final LocalDateTime to) {
|
||||
final Query createNativeQuery = entityManager
|
||||
.createNativeQuery(getFeedbackReceivedQueryTemplate(dateType, from, to));
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Object[]> resultList = createNativeQuery.getResultList();
|
||||
|
||||
final List<DataReportSeriesItem<T>> reportItems = resultList.stream()
|
||||
.map(r -> new DataReportSeriesItem<>(dateType.format((String) r[0]), ((Number) r[1]).longValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new DataReportSeries<>("FeedbackRecieved", reportItems);
|
||||
}
|
||||
|
||||
private static CriteriaQuery<Long> createCountSelectTargetsLastPoll(final CriteriaBuilder cb,
|
||||
final LocalDateTime from, final LocalDateTime to) {
|
||||
|
||||
Long start = null;
|
||||
Long end = null;
|
||||
if (from != null) {
|
||||
start = from.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
}
|
||||
if (to != null) {
|
||||
end = to.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
// count select statement
|
||||
final CriteriaQuery<Long> countSelect = cb.createQuery(Long.class);
|
||||
final Root<JpaTarget> countSelectRoot = countSelect.from(JpaTarget.class);
|
||||
countSelect.select(cb.count(countSelectRoot));
|
||||
if (start != null && end != null) {
|
||||
countSelect.where(cb.between(countSelectRoot.get(JpaTarget_.lastTargetQuery), start, end));
|
||||
} else if (from == null && to != null) {
|
||||
countSelect.where(cb.lessThanOrEqualTo(countSelectRoot.get(JpaTarget_.lastTargetQuery), end));
|
||||
} else {
|
||||
countSelect.where(cb.isNull(countSelectRoot.get(JpaTarget_.lastTargetQuery)));
|
||||
}
|
||||
return countSelect;
|
||||
}
|
||||
|
||||
private static List<InnerOuterDataReportSeries<String>> mapDistirbutionUsageResultToDataReport(
|
||||
final int topXEntries, final List<Object[]> resultListTop) {
|
||||
final List<InnerOuterDataReportSeries<String>> innerOuterReport = new ArrayList<>();
|
||||
final Map<DSName, InnerOuter> map = new LinkedHashMap<>();
|
||||
|
||||
int topXCounter = 0;
|
||||
|
||||
for (final Object[] objects : resultListTop) {
|
||||
|
||||
final boolean containsInnerOuter = map.containsKey(new DSName((String) objects[0]));
|
||||
final String name = containsInnerOuter || topXCounter < topXEntries ? (String) objects[0] : null;
|
||||
final DSName dsName = new DSName(name);
|
||||
final String version = containsInnerOuter || topXCounter < topXEntries ? (String) objects[1] : null;
|
||||
final Long count = (Long) objects[2];
|
||||
|
||||
InnerOuter innerouter = map.get(dsName);
|
||||
if (innerouter == null) {
|
||||
topXCounter++;
|
||||
innerouter = new InnerOuter(dsName);
|
||||
map.put(new DSName(name), innerouter);
|
||||
}
|
||||
innerouter.addOuter(new DSName(version), count);
|
||||
}
|
||||
|
||||
for (final InnerOuter inner : map.values()) {
|
||||
final List<DataReportSeriesItem<String>> outerReportItems = new ArrayList<>();
|
||||
|
||||
if (inner.name.getName() != null) {
|
||||
for (final InnerOuter outer : inner.outer) {
|
||||
outerReportItems.add(outer.toItem());
|
||||
}
|
||||
} else {
|
||||
outerReportItems.add(new DataReportSeriesItem<>("misc", inner.count));
|
||||
}
|
||||
|
||||
innerOuterReport.add(new InnerOuterDataReportSeries<>(
|
||||
new DataReportSeries<>("DS-Name", Collections.singletonList(inner.toItem())),
|
||||
new DataReportSeries<>("DS-Version", outerReportItems)));
|
||||
}
|
||||
|
||||
return innerOuterReport;
|
||||
}
|
||||
|
||||
private static final class InnerOuter {
|
||||
final DSName name;
|
||||
long count;
|
||||
final List<InnerOuter> outer;
|
||||
|
||||
private InnerOuter(final DSName idName) {
|
||||
name = idName;
|
||||
outer = new ArrayList<>();
|
||||
}
|
||||
|
||||
private InnerOuter(final DSName idName, final long count) {
|
||||
name = idName;
|
||||
this.count = count;
|
||||
outer = new ArrayList<>();
|
||||
}
|
||||
|
||||
private void addOuter(final DSName idName, final long count) {
|
||||
outer.add(new InnerOuter(idName, count));
|
||||
this.count += count;
|
||||
}
|
||||
|
||||
private DataReportSeriesItem<String> toItem() {
|
||||
return new DataReportSeriesItem<>(name.getName() != null ? name.getName() : "misc", count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object contains the name and the id of an entity.
|
||||
*
|
||||
*/
|
||||
private static final class DSName {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* the ID of an entity
|
||||
* @param name
|
||||
* the name of an entity
|
||||
*/
|
||||
private DSName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
private String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (name == null ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) { // NOSONAR - as this is
|
||||
// generated
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DSName other = (DSName) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DSName [name=" + name + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private String dateTimeFormatToSqlFormat(final DateType<?> datatype) {
|
||||
switch (databaseType) {
|
||||
case H2_DB_TYPE:
|
||||
return datatype.h2Format();
|
||||
case MYSQL_DB_TYPE:
|
||||
return datatype.mySqlFormat();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.PropertiesQuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.ReportManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
@@ -329,17 +328,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
return new JpaSystemManagement();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaReportManagement} bean.
|
||||
*
|
||||
* @return a new {@link ReportManagement}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ReportManagement reportManagement() {
|
||||
return new JpaReportManagement();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JpaDistributionSetManagement} bean.
|
||||
*
|
||||
|
||||
@@ -1,547 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ReportManagement;
|
||||
import org.eclipse.hawkbit.repository.ReportManagement.DateTypes;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.report.model.DataReportSeries;
|
||||
import org.eclipse.hawkbit.repository.report.model.DataReportSeriesItem;
|
||||
import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries;
|
||||
import org.eclipse.hawkbit.repository.report.model.SeriesTime;
|
||||
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.auditing.AuditingHandler;
|
||||
import org.springframework.data.auditing.CurrentDateTimeProvider;
|
||||
import org.springframework.data.auditing.DateTimeProvider;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("Report Management")
|
||||
public class ReportManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
private static final String TEST_MESSAGE = "some message";
|
||||
|
||||
@Autowired
|
||||
private ReportManagement reportManagement;
|
||||
|
||||
@Autowired
|
||||
private AuditingHandler auditingHandler;
|
||||
|
||||
@After
|
||||
public void afterTest() {
|
||||
auditingHandler.setDateTimeProvider(CurrentDateTimeProvider.INSTANCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests correct statistics calculation including a correct cache evict.")
|
||||
public void targetsCreatedOverPeriod() {
|
||||
|
||||
// the maximum months going back from now
|
||||
// create more targets than asking the report so we can check if the
|
||||
// report is returning the
|
||||
// correct timeframe
|
||||
final int maxMonthBackAmountCreateTargets = 10;
|
||||
final int maxMonthBackAmountReportTargets = 4;
|
||||
|
||||
final DynamicDateTimeProvider dynamicDateTimeProvider = new DynamicDateTimeProvider();
|
||||
auditingHandler.setDateTimeProvider(dynamicDateTimeProvider);
|
||||
|
||||
for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) {
|
||||
dynamicDateTimeProvider.nowMinusMonths(month);
|
||||
testdataFactory.createTarget("t" + month);
|
||||
}
|
||||
|
||||
final LocalDateTime to = LocalDateTime.now();
|
||||
final LocalDateTime from = to.minusMonths(maxMonthBackAmountReportTargets);
|
||||
|
||||
DataReportSeries<LocalDate> targetsCreatedOverPeriod = reportManagement
|
||||
.targetsCreatedOverPeriod(DateTypes.perMonth(), from, to);
|
||||
|
||||
// +1 because we go back #maxMonthBackAmountReportTargets but in the
|
||||
// report the current month
|
||||
// is included for sure, so from this month we go back
|
||||
assertThat(targetsCreatedOverPeriod.getData()).as("created over period has wrong size")
|
||||
.hasSize(maxMonthBackAmountReportTargets + 1);
|
||||
for (final DataReportSeriesItem<LocalDate> reportItem : targetsCreatedOverPeriod.getData()) {
|
||||
// only one target is created for each month
|
||||
assertThat(reportItem.getData().intValue()).as("Target for each month").isEqualTo(1);
|
||||
}
|
||||
|
||||
// check cache evict
|
||||
for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) {
|
||||
dynamicDateTimeProvider.nowMinusMonths(month);
|
||||
testdataFactory.createTarget("t2" + month);
|
||||
}
|
||||
targetsCreatedOverPeriod = reportManagement.targetsCreatedOverPeriod(DateTypes.perMonth(), from, to);
|
||||
for (final DataReportSeriesItem<LocalDate> reportItem : targetsCreatedOverPeriod.getData()) {
|
||||
assertThat(reportItem.getData().intValue()).as("Target for each month").isEqualTo(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests correct statistics calculation including a correct cache evict.")
|
||||
public void targetsFeedbackOverPeriod() {
|
||||
|
||||
// the maximum months going back from now
|
||||
// create more targets than asking the report so we can check if the
|
||||
// report is returning the
|
||||
// correct timeframe
|
||||
final int maxMonthBackAmountCreateTargets = 10;
|
||||
final int maxMonthBackAmountReportTargets = 4;
|
||||
|
||||
final LocalDateTime to = LocalDateTime.now();
|
||||
final LocalDateTime from = to.minusMonths(maxMonthBackAmountReportTargets);
|
||||
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds");
|
||||
|
||||
final DynamicDateTimeProvider dynamicDateTimeProvider = new DynamicDateTimeProvider();
|
||||
auditingHandler.setDateTimeProvider(dynamicDateTimeProvider);
|
||||
|
||||
for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) {
|
||||
dynamicDateTimeProvider.nowMinusMonths(month);
|
||||
final Target createTarget = testdataFactory.createTarget("t" + month);
|
||||
final DistributionSetAssignmentResult result = assignDistributionSet(distributionSet,
|
||||
Lists.newArrayList(createTarget));
|
||||
controllerManagement.registerRetrieved(result.getActions().get(0),
|
||||
"Controller retrieved update action and should start now the download.");
|
||||
}
|
||||
DataReportSeries<LocalDate> feedbackReceivedOverTime = reportManagement
|
||||
.feedbackReceivedOverTime(DateTypes.perMonth(), from, to);
|
||||
// +1 because we go back #maxMonthBackAmountReportTargets but in the
|
||||
// report the current month
|
||||
// is included for sure, so from this month we go back
|
||||
assertThat(feedbackReceivedOverTime.getData()).as("feedback receiver has wrong data size")
|
||||
.hasSize(maxMonthBackAmountReportTargets + 1);
|
||||
for (final DataReportSeriesItem<LocalDate> reportItem : feedbackReceivedOverTime.getData()) {
|
||||
// only one target feedback is created for each month
|
||||
assertThat(reportItem.getData().intValue()).as("data size is wrong").isEqualTo(1);
|
||||
}
|
||||
|
||||
// check cache evict
|
||||
for (int month = 0; month < maxMonthBackAmountCreateTargets; month++) {
|
||||
dynamicDateTimeProvider.nowMinusMonths(month);
|
||||
final Target createTarget = testdataFactory.createTarget("t2" + month);
|
||||
final DistributionSetAssignmentResult result = assignDistributionSet(distributionSet,
|
||||
Lists.newArrayList(createTarget));
|
||||
controllerManagement.registerRetrieved(result.getActions().get(0),
|
||||
"Controller retrieved update action and should start now the download.");
|
||||
}
|
||||
feedbackReceivedOverTime = reportManagement.feedbackReceivedOverTime(DateTypes.perMonth(), from, to);
|
||||
for (final DataReportSeriesItem<LocalDate> reportItem : feedbackReceivedOverTime.getData()) {
|
||||
assertThat(reportItem.getData().intValue()).as("report item has wrong data size").isEqualTo(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests correct statistics calculation including a correct cache evict.")
|
||||
public void distributionUsageInstalled() {
|
||||
final Target knownTarget1 = testdataFactory.createTarget("t1");
|
||||
final Target knownTarget2 = testdataFactory.createTarget("t2");
|
||||
final Target knownTarget3 = testdataFactory.createTarget("t3");
|
||||
final Target knownTarget4 = testdataFactory.createTarget("t4");
|
||||
final Target knownTarget5 = testdataFactory.createTarget("t5");
|
||||
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP);
|
||||
final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT);
|
||||
final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS);
|
||||
|
||||
final DistributionSet distributionSet1 = testdataFactory.createDistributionSet("ds1", "0.0.0", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
final DistributionSet distributionSet11 = testdataFactory.createDistributionSet("ds1", "0.0.1", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet("ds2", "0.0.2", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
final DistributionSet distributionSet3 = testdataFactory.createDistributionSet("ds3", "0.0.3", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
|
||||
// ds1(0.0.0)=[target1,target2], ds1(0.0.1)=[target3]
|
||||
assignDistributionSet(distributionSet1.getId(), knownTarget1.getControllerId());
|
||||
assignDistributionSet(distributionSet1.getId(), knownTarget2.getControllerId());
|
||||
assignDistributionSet(distributionSet11.getId(), knownTarget3.getControllerId());
|
||||
|
||||
// ds2=[target4]
|
||||
assignDistributionSet(distributionSet2.getId(), knownTarget4.getControllerId());
|
||||
|
||||
// ds3=[target5] --> ONLY ASSIGNED AND NOT INSTALLED
|
||||
assignDistributionSet(distributionSet3.getId(), knownTarget5.getControllerId());
|
||||
|
||||
// set installed status
|
||||
testdataFactory.sendUpdateActionStatusToTargets(
|
||||
Lists.newArrayList(knownTarget1, knownTarget2, knownTarget3, knownTarget4), Status.FINISHED,
|
||||
Collections.singletonList(TEST_MESSAGE));
|
||||
|
||||
List<InnerOuterDataReportSeries<String>> distributionUsage = reportManagement.distributionUsageInstalled(100);
|
||||
|
||||
for (final InnerOuterDataReportSeries<String> innerOuterDataReportSeries : distributionUsage) {
|
||||
|
||||
// innerseries only have one data of the name and the total count
|
||||
final DataReportSeriesItem<String> dataReportSeriesItem = innerOuterDataReportSeries.getInnerSeries()
|
||||
.getData()[0];
|
||||
if (dataReportSeriesItem.getType().equals("ds1")) {
|
||||
// total count of three because ds1 has two different versions
|
||||
assertThat(dataReportSeriesItem.getData()).as("Version/Item type of DistributionSet 1 in statistics")
|
||||
.isEqualTo(3L);
|
||||
final DataReportSeriesItem<String>[] outerData = innerOuterDataReportSeries.getOuterSeries().getData();
|
||||
assertThat(Arrays.stream(outerData).map(DataReportSeriesItem::getType).collect(Collectors.toList()))
|
||||
.as("versio item contains wrong version").contains("0.0.0", "0.0.1");
|
||||
} else if (dataReportSeriesItem.getType().equals("ds2")) {
|
||||
assertThat(dataReportSeriesItem.getData()).as("Version/Item type of DistributionSet 2 in statistics")
|
||||
.isEqualTo(1L);
|
||||
final DataReportSeriesItem<String>[] outerData = innerOuterDataReportSeries.getOuterSeries().getData();
|
||||
assertThat(outerData).as("Version/Item type has wrong size").hasSize(1);
|
||||
assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 2 in statistics")
|
||||
.isEqualTo("0.0.2");
|
||||
} else if (dataReportSeriesItem.getType().equals("ds3")) {
|
||||
|
||||
assertThat(dataReportSeriesItem.getData()).as("Version/Item type of DistributionSet 3 in statistics")
|
||||
.isEqualTo(0L);
|
||||
final DataReportSeriesItem<String>[] outerData = innerOuterDataReportSeries.getOuterSeries().getData();
|
||||
assertThat(outerData).as("Version/Item type has wrong size").hasSize(1);
|
||||
assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 3 in statistics")
|
||||
.isEqualTo("0.0.3");
|
||||
} else {
|
||||
fail("no assertion count for distribution set " + dataReportSeriesItem.getType());
|
||||
}
|
||||
}
|
||||
|
||||
// Test cache evict
|
||||
final Target knownTarget6 = testdataFactory.createTarget("t6");
|
||||
assignDistributionSet(distributionSet1.getId(), knownTarget6.getControllerId());
|
||||
testdataFactory.sendUpdateActionStatusToTargets(Lists.newArrayList(knownTarget6), Status.FINISHED,
|
||||
Collections.singletonList(TEST_MESSAGE));
|
||||
distributionUsage = reportManagement.distributionUsageInstalled(100);
|
||||
for (final InnerOuterDataReportSeries<String> innerOuterDataReportSeries : distributionUsage) {
|
||||
final DataReportSeriesItem<String> dataReportSeriesItem = innerOuterDataReportSeries.getInnerSeries()
|
||||
.getData()[0];
|
||||
if (dataReportSeriesItem.getType().equals("ds1")) {
|
||||
assertThat(dataReportSeriesItem.getData()).as("Data report item number").isEqualTo(4L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests correct statistics calculation including a correct cache evict.")
|
||||
public void targetStatusReport() {
|
||||
|
||||
final long knownErrorCount = 5;
|
||||
final long knownSyncCount = 4;
|
||||
final long knownPendingCount = 3;
|
||||
final long knownRegCount = 2;
|
||||
final long knownUnknownCount = 1;
|
||||
|
||||
createTargetsWithStatus("error", knownErrorCount, TargetUpdateStatus.ERROR);
|
||||
createTargetsWithStatus("snyc", knownSyncCount, TargetUpdateStatus.IN_SYNC);
|
||||
createTargetsWithStatus("pending", knownPendingCount, TargetUpdateStatus.PENDING);
|
||||
createTargetsWithStatus("reg", knownRegCount, TargetUpdateStatus.REGISTERED);
|
||||
createTargetsWithStatus("unknown", knownUnknownCount, TargetUpdateStatus.UNKNOWN);
|
||||
|
||||
DataReportSeries<TargetUpdateStatus> targetStatus = reportManagement.targetStatus();
|
||||
for (final DataReportSeriesItem<TargetUpdateStatus> reportItem : targetStatus.getData()) {
|
||||
|
||||
switch (reportItem.getType()) {
|
||||
case ERROR:
|
||||
assertThat(reportItem.getData()).as("ERROR count for targets in statistics").isEqualTo(knownErrorCount);
|
||||
break;
|
||||
case IN_SYNC:
|
||||
assertThat(reportItem.getData()).as("IN_SYNC count for targets in statistics")
|
||||
.isEqualTo(knownSyncCount);
|
||||
break;
|
||||
case PENDING:
|
||||
assertThat(reportItem.getData()).as("PENDING count for targets in statistics")
|
||||
.isEqualTo(knownPendingCount);
|
||||
break;
|
||||
case REGISTERED:
|
||||
assertThat(reportItem.getData()).as("REGISTERED count for targets in statistics")
|
||||
.isEqualTo(knownRegCount);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
assertThat(reportItem.getData()).as("UNKNOWN count for targets in statistics")
|
||||
.isEqualTo(knownUnknownCount);
|
||||
break;
|
||||
default:
|
||||
fail("missing case for unknown target update status " + reportItem.getType());
|
||||
}
|
||||
}
|
||||
|
||||
// test cache evict
|
||||
createTargetsWithStatus("error2", knownErrorCount, TargetUpdateStatus.ERROR);
|
||||
createTargetsWithStatus("snyc2", knownSyncCount, TargetUpdateStatus.IN_SYNC);
|
||||
createTargetsWithStatus("pending2", knownPendingCount, TargetUpdateStatus.PENDING);
|
||||
createTargetsWithStatus("reg2", knownRegCount, TargetUpdateStatus.REGISTERED);
|
||||
createTargetsWithStatus("unknown2", knownUnknownCount, TargetUpdateStatus.UNKNOWN);
|
||||
|
||||
targetStatus = reportManagement.targetStatus();
|
||||
for (final DataReportSeriesItem<TargetUpdateStatus> reportItem : targetStatus.getData()) {
|
||||
|
||||
switch (reportItem.getType()) {
|
||||
case ERROR:
|
||||
assertThat(reportItem.getData()).as("ERROR count for targets in statistics")
|
||||
.isEqualTo(knownErrorCount * 2);
|
||||
break;
|
||||
case IN_SYNC:
|
||||
assertThat(reportItem.getData()).as("IN_SYNC count for targets in statistics")
|
||||
.isEqualTo(knownSyncCount * 2);
|
||||
break;
|
||||
case PENDING:
|
||||
assertThat(reportItem.getData()).as("PENDING count for targets in statistics")
|
||||
.isEqualTo(knownPendingCount * 2);
|
||||
break;
|
||||
case REGISTERED:
|
||||
assertThat(reportItem.getData()).as("REGISTERED count for targets in statistics")
|
||||
.isEqualTo(knownRegCount * 2);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
assertThat(reportItem.getData()).as("UNKNOWN count for targets in statistics")
|
||||
.isEqualTo(knownUnknownCount * 2);
|
||||
break;
|
||||
default:
|
||||
fail("missing case for unknown target update status " + reportItem.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests correct statistics calculation including a correct cache evict.")
|
||||
public void topXDistributionUsage() {
|
||||
final Target knownTarget1 = testdataFactory.createTarget("t1");
|
||||
final Target knownTarget2 = testdataFactory.createTarget("t2");
|
||||
final Target knownTarget3 = testdataFactory.createTarget("t3");
|
||||
final Target knownTarget4 = testdataFactory.createTarget("t4");
|
||||
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP);
|
||||
final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT);
|
||||
final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS);
|
||||
|
||||
final DistributionSet distributionSet1 = testdataFactory.createDistributionSet("ds1", "0.0.0", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
final DistributionSet distributionSet11 = testdataFactory.createDistributionSet("ds1", "0.0.1", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet("ds2", "0.0.2", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
final DistributionSet distributionSet3 = testdataFactory.createDistributionSet("ds3", "0.0.3", standardDsType,
|
||||
Lists.newArrayList(os, jvm, ah));
|
||||
|
||||
// ds1(0.0.0)=[target1,target2], ds1(0.0.1)=[target3]
|
||||
assignDistributionSet(distributionSet1.getId(), knownTarget1.getControllerId());
|
||||
assignDistributionSet(distributionSet1.getId(), knownTarget2.getControllerId());
|
||||
assignDistributionSet(distributionSet11.getId(), knownTarget3.getControllerId());
|
||||
|
||||
// ds2=[target4]
|
||||
assignDistributionSet(distributionSet2.getId(), knownTarget4.getControllerId());
|
||||
|
||||
// expect: ds1(0.0.0)=[target1,target2], ds1(0.0.1)=[target3],
|
||||
// ds2=[target4], ds3=[]
|
||||
|
||||
List<InnerOuterDataReportSeries<String>> distributionUsage = reportManagement.distributionUsageAssigned(100);
|
||||
|
||||
for (final InnerOuterDataReportSeries<String> innerOuterDataReportSeries : distributionUsage) {
|
||||
|
||||
// innerseries only have one data of the name and the total count
|
||||
final DataReportSeriesItem<String> dataReportSeriesItem = innerOuterDataReportSeries.getInnerSeries()
|
||||
.getData()[0];
|
||||
if (dataReportSeriesItem.getType().equals("ds1")) {
|
||||
|
||||
// total count of three because ds1 has two different versions
|
||||
assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 1 in statistics")
|
||||
.isEqualTo(3L);
|
||||
|
||||
final DataReportSeriesItem<String>[] outerData = innerOuterDataReportSeries.getOuterSeries().getData();
|
||||
assertThat(Arrays.stream(outerData).map(DataReportSeriesItem::getType).collect(Collectors.toList()))
|
||||
.as("Out series contains wrong version").contains("0.0.0", "0.0.1");
|
||||
|
||||
} else if (dataReportSeriesItem.getType().equals("ds2")) {
|
||||
assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 2 in statistics")
|
||||
.isEqualTo(1L);
|
||||
final DataReportSeriesItem<String>[] outerData = innerOuterDataReportSeries.getOuterSeries().getData();
|
||||
assertThat(outerData).as("out series has wrong size").hasSize(1);
|
||||
assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 2 in statistics")
|
||||
.isEqualTo("0.0.2");
|
||||
|
||||
} else if (dataReportSeriesItem.getType().equals("ds3")) {
|
||||
assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 3 in statistics")
|
||||
.isEqualTo(0L);
|
||||
final DataReportSeriesItem<String>[] outerData = innerOuterDataReportSeries.getOuterSeries().getData();
|
||||
assertThat(outerData).as("out series has wrong size").hasSize(1);
|
||||
assertThat(outerData[0].getType()).as("Version/Item type of DistributionSet 3 in statistics")
|
||||
.isEqualTo("0.0.3");
|
||||
} else {
|
||||
fail("no assertion count for distribution set " + dataReportSeriesItem.getType());
|
||||
}
|
||||
}
|
||||
|
||||
// test cache evict
|
||||
final Target knownTarget5 = testdataFactory.createTarget("t5");
|
||||
assignDistributionSet(distributionSet1.getId(), knownTarget5.getControllerId());
|
||||
distributionUsage = reportManagement.distributionUsageAssigned(100);
|
||||
for (final InnerOuterDataReportSeries<String> innerOuterDataReportSeries : distributionUsage) {
|
||||
final DataReportSeriesItem<String> dataReportSeriesItem = innerOuterDataReportSeries.getInnerSeries()
|
||||
.getData()[0];
|
||||
if (dataReportSeriesItem.getType().equals("ds1")) {
|
||||
assertThat(dataReportSeriesItem.getData()).as("Total count of DistributionSet 1 in statistics")
|
||||
.isEqualTo(4L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests correct statistics calculation including a correct cache evict.")
|
||||
public void lastPollTargets() {
|
||||
// --- prepare ---
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
final int knownTargetsPollLastHour = 2;
|
||||
final int knownTargetsPollLastDay = 3;
|
||||
final int knownTargetsPollLastWeek = 4;
|
||||
final int knownTargetsPollLastMonth = 5;
|
||||
final int knownTargetsPollLastYear = 6;
|
||||
final int knownTargetsNeverPoll = 7;
|
||||
// never
|
||||
createTargets("neverPoll", knownTargetsNeverPoll, null);
|
||||
// hour
|
||||
createTargets("hourPoll", knownTargetsPollLastHour, now.minusMinutes(59));
|
||||
// day
|
||||
createTargets("dayPoll", knownTargetsPollLastDay, now.minusHours(23));
|
||||
// week
|
||||
createTargets("weekPoll", knownTargetsPollLastWeek, now.minusDays(6));
|
||||
// month
|
||||
createTargets("monthPoll", knownTargetsPollLastMonth, now.minusWeeks(3));
|
||||
// year
|
||||
createTargets("yearPoll", knownTargetsPollLastYear, now.minusMonths(11));
|
||||
|
||||
// --- Test ---
|
||||
DataReportSeries<SeriesTime> targetsNotLastPoll = reportManagement.targetsLastPoll();
|
||||
DataReportSeriesItem<SeriesTime>[] data = targetsNotLastPoll.getData();
|
||||
|
||||
// --- Verfiy ---
|
||||
|
||||
// verify hour
|
||||
assertThat(data[0].getType()).as("Series time").isEqualTo(SeriesTime.HOUR);
|
||||
assertThat(data[0].getData()).as("Targets poll last hour").isEqualTo((long) knownTargetsPollLastHour);
|
||||
// verify day
|
||||
assertThat(data[1].getType()).as("Series time").isEqualTo(SeriesTime.DAY);
|
||||
assertThat(data[1].getData()).as("Targets poll last day").isEqualTo((long) knownTargetsPollLastDay);
|
||||
// verify week
|
||||
assertThat(data[2].getType()).as("Series time").isEqualTo(SeriesTime.WEEK);
|
||||
assertThat(data[2].getData()).as("Targets poll last week").isEqualTo((long) knownTargetsPollLastWeek);
|
||||
|
||||
// test cache evict
|
||||
createTargets("hourPoll2", knownTargetsPollLastHour, now.minusMinutes(59));
|
||||
targetsNotLastPoll = reportManagement.targetsLastPoll();
|
||||
data = targetsNotLastPoll.getData();
|
||||
assertThat(data[0].getType()).as("Series time").isEqualTo(SeriesTime.HOUR);
|
||||
assertThat(data[0].getData()).as("Targets poll last hour").isEqualTo((long) knownTargetsPollLastHour * 2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(tenantId = "mytenant", allSpPermissions = true)
|
||||
@Description("Ensures that targets created report is tenant aware and only creates a report for the current tenant.")
|
||||
public void targetsCreatedOverPeriodMultiTenancyAware() throws Exception {
|
||||
final int targetCreateAmount = 10;
|
||||
|
||||
// create targets for another tenant
|
||||
securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("user", "anotherTenant"), () -> {
|
||||
for (int index = 0; index < targetCreateAmount; index++) {
|
||||
testdataFactory.createTarget("t" + index);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
// ensure targets has been created for 'anotherTenant'
|
||||
final Slice<Target> targetsForAnotherTenant = securityRule.runAs(
|
||||
WithSpringAuthorityRule.withUserAndTenant("user", "anotherTenant"),
|
||||
() -> targetManagement.findTargetsAll(new PageRequest(0, 1000)));
|
||||
assertThat(targetsForAnotherTenant).as("targets has wrong size").hasSize(targetCreateAmount);
|
||||
|
||||
final LocalDateTime to = LocalDateTime.now();
|
||||
final LocalDateTime from = to.minusMonths(targetCreateAmount);
|
||||
// now retrieve the report for the 'mytenant'
|
||||
final DataReportSeries<LocalDate> targetsCreatedOverPeriod = reportManagement
|
||||
.targetsCreatedOverPeriod(DateTypes.perMonth(), from, to);
|
||||
assertThat(targetsCreatedOverPeriod.getData()).as("final no targets should final be created for this tenant")
|
||||
.hasSize(0);
|
||||
|
||||
}
|
||||
|
||||
private void createTargets(final String prefix, final int amount, final LocalDateTime lastTargetQuery) {
|
||||
for (int index = 0; index < amount; index++) {
|
||||
final JpaTarget createTarget = (JpaTarget) testdataFactory.createTarget(prefix + index);
|
||||
if (lastTargetQuery != null) {
|
||||
createTarget
|
||||
.setLastTargetQuery(lastTargetQuery.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
||||
targetRepository.save(createTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createTargetsWithStatus(final String prefix, final long amount, final TargetUpdateStatus status) {
|
||||
for (int index = 0; index < amount; index++) {
|
||||
final JpaTarget target = new JpaTarget(prefix + index);
|
||||
target.setUpdateStatus(status);
|
||||
targetRepository.save(target);
|
||||
}
|
||||
}
|
||||
|
||||
private class DynamicDateTimeProvider implements DateTimeProvider {
|
||||
|
||||
private Calendar datetime = Calendar.getInstance();
|
||||
|
||||
@Override
|
||||
public Calendar getNow() {
|
||||
return datetime;
|
||||
}
|
||||
|
||||
public void now() {
|
||||
datetime = Calendar.getInstance();
|
||||
}
|
||||
|
||||
public void nowMinusMonths(final int amount) {
|
||||
datetime = Calendar.getInstance();
|
||||
datetime.add(Calendar.MONTH, -amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param datetime
|
||||
* the datetime to set
|
||||
*/
|
||||
public void setDatetime(final Calendar datetime) {
|
||||
this.datetime = datetime;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user