com.epam.ta.reportportal.database.dao.TestItemRepositoryCustomImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.epam.ta.reportportal.database.dao.TestItemRepositoryCustomImpl.java

Source

/*
 * Copyright 2016 EPAM Systems
 * 
 * 
 * This file is part of EPAM Report Portal.
 * https://github.com/reportportal/commons-dao
 * 
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.epam.ta.reportportal.database.dao;

import static com.epam.ta.reportportal.database.search.UpdateStatisticsQueryBuilder.*;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.StreamSupport;

import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.Fields;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.epam.ta.reportportal.commons.DbUtils;
import com.epam.ta.reportportal.database.Time;
import com.epam.ta.reportportal.database.entity.*;
import com.epam.ta.reportportal.database.entity.item.TestItem;
import com.epam.ta.reportportal.database.entity.item.issue.TestItemIssueType;
import com.epam.ta.reportportal.database.entity.statistics.StatisticSubType;
import com.epam.ta.reportportal.database.search.ModifiableQueryBuilder;

/**
 * Implementation of Test Items repository routines
 *
 * @author Andrei Varabyeu
 * @author Andrei_Ramanchuk
 *
 */
public class TestItemRepositoryCustomImpl implements TestItemRepositoryCustom {

    private static final String ID_REFERENCE = "id";
    private static final String LAUNCH_REFERENCE = "launchRef";
    private static final String ITEM_REFERENCE = "testItemRef";
    private static final String ISSUE_TYPE = "issue.issueType";
    private static final String ISSUE_TICKET = "issue.externalSystemIssues";
    private static final String ISSUE_DESCRIPTION = "issue.issueDescription";
    private static final String ISSUE = "issue";
    private static final String HAS_CHILD = "has_childs";
    private static final String START_TIME = "start_time";

    public static final int HISTORY_LIMIT = 2000;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void updateExecutionStatistics(TestItem item) {
        mongoTemplate.updateMulti(getItemQuery(item), fromItemStatusAware(item.getStatus(), 1, 1), TestItem.class);
    }

    @Override
    public void updateIssueStatistics(TestItem item, Project.Configuration settings) {
        mongoTemplate.updateMulti(getItemQuery(item),
                fromIssueTypeAware(settings.getByLocator(item.getIssue().getIssueType()), 1), TestItem.class);
    }

    @Override
    public void dropIssueStatisticsType(String id, StatisticSubType type) {
        mongoTemplate.updateMulti(query(where(ID_REFERENCE).is(id)), dropIssueTypeAware(type), TestItem.class);
    }

    @Override
    public void updateHasChilds(String id, boolean hasChildren) {
        mongoTemplate.updateFirst(query(where(ID_REFERENCE).is(id)), Update.update("has_childs", hasChildren),
                TestItem.class);
    }

    @Override
    public boolean hasDescendants(Object... id) {
        return mongoTemplate.count(getItemDescendantsQuery(id), TestItem.class) > 0;
    }

    @Override
    public List<TestItem> findDescendants(String... id) {
        return mongoTemplate.find(getItemDescendantsQuery((Object[]) id), TestItem.class);
    }

    @Override
    public void resetIssueStatistics(TestItem item, Project.Configuration settings) {
        mongoTemplate.updateMulti(getItemQuery(item),
                fromIssueTypeAware(settings.getByLocator(item.getIssue().getIssueType()), -1), TestItem.class);
    }

    @Override
    public void resetExecutionStatistics(TestItem item) {
        mongoTemplate.updateMulti(getItemQuery(item), fromItemStatusAware(item.getStatus(), -1, -1),
                TestItem.class);
    }

    @Override
    public void deleteIssueStatistics(TestItem item) {
        mongoTemplate.updateMulti(getItemQuery(item), fromIssueTypeAware(item, true), TestItem.class);
    }

    @Override
    public void deleteExecutionStatistics(TestItem item) {
        mongoTemplate.updateMulti(getItemQuery(item), fromItemStatusAware(item, true), TestItem.class);
    }

    private Query getItemQuery(TestItem item) {
        List<String> fullPath = new ArrayList<>(item.getPath());
        fullPath.add(item.getId());
        return query(where(LAUNCH_REFERENCE).is(item.getLaunchRef())).addCriteria(where("_id").in(fullPath))
                .addCriteria(where("statistics").exists(true));
    }

    private Query getItemDescendantsQuery(Object... id) {
        return new Query().addCriteria(where("path").in(id));
    }

    @Override
    public List<TestItem> findByLaunch(Launch launch) {
        return mongoTemplate.find(query(where(LAUNCH_REFERENCE).is(launch.getId())), TestItem.class);
    }

    @Override
    public List<TestItem> findIdsByLaunch(Iterable<Launch> launches) {
        Query q = query(where(LAUNCH_REFERENCE).in(obtainIds(launches)));
        q.fields().include(ID_REFERENCE);
        return mongoTemplate.find(q, TestItem.class);
    }

    @Override
    public Map<String, String> findPathNames(Iterable<String> path) {
        Query q = query(where("_id").in(toObjId(path)));
        q.fields().include("name");
        List<TestItem> testItems = mongoTemplate.find(q, TestItem.class);
        LinkedHashMap<String, String> pathNames = new LinkedHashMap<>(testItems.size());
        for (TestItem testItem : testItems) {
            pathNames.put(testItem.getId(), testItem.getName());
        }
        return pathNames;
    }

    private Collection<ObjectId> toObjId(Iterable<String> path) {
        List<ObjectId> ids = new ArrayList<>();
        for (String id : path) {
            ids.add(new ObjectId(id));
        }
        return ids;
    }

    private Collection<String> obtainIds(Iterable<Launch> launches) {
        return StreamSupport.stream(launches.spliterator(), false).map(Launch::getId).collect(toList());
    }

    @Override
    public List<TestItem> findModifiedLaterAgo(Time period, Status status, Launch launch, boolean hasChilds) {
        Query q = ModifiableQueryBuilder.findModifiedLaterThanPeriod(period, status)
                .addCriteria(where(LAUNCH_REFERENCE).is(launch.getId()))
                .addCriteria(where("has_childs").is(hasChilds));
        return mongoTemplate.find(q, TestItem.class);
    }

    @Override
    public List<TestItem> findModifiedLaterAgo(Time period, Status status, Launch launch) {
        Query q = ModifiableQueryBuilder.findModifiedLaterThanPeriod(period, status)
                .addCriteria(where(LAUNCH_REFERENCE).is(launch.getId()));
        return mongoTemplate.find(q, TestItem.class);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public List<String> findDistinctValues(String launchId, String containsValue, String distinctBy) {
        Aggregation aggregation = newAggregation(match(where(LAUNCH_REFERENCE).is(launchId)), unwind(distinctBy),
                match(where(distinctBy).regex("(?i).*" + Pattern.quote(containsValue) + ".*")), group(distinctBy));
        AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, TestItem.class, Map.class);
        return result.getMappedResults().stream().map(entry -> entry.get("_id").toString()).collect(toList());
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public List<String> getUniqueTicketsCount(List<Launch> launches) {
        List<String> launchIds = launches.stream().map(Launch::getId).collect(toList());
        Aggregation aggregation = newAggregation(match(where(LAUNCH_REFERENCE).in(launchIds)),
                match(where(ISSUE_TICKET).exists(true)), unwind(ISSUE_TICKET), group(ISSUE_TICKET));
        // Count be as
        // Aggregation.group("issue.externalSystemIssues").count().as("count");
        // but keep a whole
        AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, TestItem.class, Map.class);
        return result.getMappedResults().stream().map(entry -> entry.get("ticketId").toString()).collect(toList());
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.epam.ta.reportportal.database.dao.TestItemRepositoryCustom#
     * getMostFailedTestCases(java.util.List, java.lang.String)
     * 
     * Most Failed Test Cases widget related method
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public Map<String, String> getMostFailedTestCases(List<Launch> launches, String criteria) {
        Map<String, String> output = new HashMap<>();
        List<String> launchIds = launches.stream().map(Launch::getId).collect(toList());

        GroupOperation operationTotal = new GroupOperation(Fields.fields("$name")).count().as("count");
        Aggregation aggregationTotal = newAggregation(match(where(LAUNCH_REFERENCE).in(launchIds)),
                match(where(HAS_CHILD).is(false)), operationTotal);
        AggregationResults<Map> resultTotal = mongoTemplate.aggregate(aggregationTotal, TestItem.class, Map.class);
        Map<String, String> values = resultTotal.getMappedResults().stream()
                .collect(toMap(key -> key.get("_id").toString(), value -> value.get("count").toString()));

        GroupOperation operation = new GroupOperation(Fields.fields("$name")).count().as("count").last("$startTime")
                .as("last");
        Aggregation aggregation = newAggregation(match(where(LAUNCH_REFERENCE).in(launchIds)),
                match(where(criteria).is(1)), match(where(HAS_CHILD).is(false)), operation);

        AggregationResults<Map> result = mongoTemplate.aggregate(aggregation, TestItem.class, Map.class);
        for (Map<String, ?> entry : result.getMappedResults()) {
            String itemName = String.valueOf(entry.get("_id"));
            String count = String.valueOf(entry.get("count"));
            Date date = (Date) entry.get("last");
            String total = values.get(itemName);
            // FIXME Update dirty # separator with common case
            // And update after {@link MostFailedTestCasesFilterStrategy}
            output.put(itemName, count + "#" + date.getTime() + "#" + total);
        }
        return output;
    }

    @Override
    public boolean hasLogs(Iterable<TestItem> items) {
        Query query = query(where(ITEM_REFERENCE).in(DbUtils.toIds(items)));
        return mongoTemplate.count(query, Log.class) > 0;
    }

    @Override
    public List<TestItem> loadItemsHistory(List<TestItem> items, List<String> launchesIds, List<String> parentIds) {
        if (items == null || launchesIds == null) {
            return new ArrayList<>();
        }
        Query query = query(getHistoryLaunchPathCriteria(launchesIds, items.get(0)))
                .addCriteria(getItemsHistoryCriteria(items));

        if (parentIds != null) {
            query.addCriteria(where("parent").in(parentIds));
        }
        query.limit(HISTORY_LIMIT);
        query.fields().include("name");
        query.fields().include("start_time");
        query.fields().include("end_time");
        /* For UI: links level detector */
        query.fields().include("has_childs");
        query.fields().include("launchRef");
        query.fields().include("issue");
        query.fields().include("status");
        query.fields().include("tags");
        query.fields().include("itemDescription");
        query.fields().include("statistics");
        query.fields().include("type");
        query.fields().include(ID_REFERENCE);
        return mongoTemplate.find(query, TestItem.class);
    }

    @Override
    public List<TestItem> findTestItemWithInvestigated(String launchId) {
        Criteria internalIssues = new Criteria().andOperator(where(LAUNCH_REFERENCE).is(launchId),
                where(ISSUE_TYPE).ne(TestItemIssueType.TO_INVESTIGATE.name()),
                where(ISSUE_DESCRIPTION).exists(true));

        Criteria externalIssues = new Criteria().andOperator(where(LAUNCH_REFERENCE).is(launchId),
                where(ISSUE_TYPE).exists(true), where(ISSUE_TICKET).exists(true));

        Query query = query(new Criteria().orOperator(internalIssues, externalIssues));

        query.limit(HISTORY_LIMIT);
        query.fields().include("name");
        query.fields().include("launchRef");
        query.fields().include("issue");
        query.fields().include("status");
        query.fields().include(ID_REFERENCE);

        query.fields().include("start_time");

        return mongoTemplate.find(query, TestItem.class);
    }

    @Override
    public boolean hasTestItemsAddedLately(Time period, Launch launch, Status status) {
        Query query = ModifiableQueryBuilder.findModifiedLately(period)
                .addCriteria(where(LAUNCH_REFERENCE).is(launch.getId()))
                .addCriteria(where(HasStatus.STATUS).is(status.name()));
        return (mongoTemplate.count(query, TestItem.class) > 0);
    }

    @Override
    public List<TestItem> findInIssueTypeItems(String issueType, String launchId) {
        Query query = query(where(LAUNCH_REFERENCE).is(launchId))
                .addCriteria(where(ISSUE_TYPE).regex(Pattern.quote(issueType)));
        return mongoTemplate.find(query, TestItem.class);
    }

    @Override
    public List<String> findItemIdsByLaunchRef(List<String> launchRef) {
        Aggregation aggregation = newAggregation(match(where("launchRef").in(launchRef)), group("id"));
        AggregationResults<Map> aggregationResults = mongoTemplate.aggregate(aggregation, TestItem.class,
                Map.class);
        return aggregationResults.getMappedResults().stream().map(it -> it.get("_id").toString()).collect(toList());
    }

    /**
     * Create part of history criteria. Define launch id, and path size
     * conditions.
     *
     * @param launchesIds
     * @param item
     * @return
     */
    private Criteria getHistoryLaunchPathCriteria(List<String> launchesIds, TestItem item) {
        return where(LAUNCH_REFERENCE).in(launchesIds).and("path").size(item.getPath().size());
    }

    /**
     * Create {@link Criteria} object for items history selecting Define name
     * type conditions.
     *
     * @param testItems
     * @return
     */
    private Criteria getItemsHistoryCriteria(List<TestItem> testItems) {
        Criteria criteria = new Criteria();
        Criteria[] itemCriteries = new Criteria[testItems.size()];

        for (int i = 0; i < testItems.size(); i++) {
            TestItem testItem = testItems.get(i);
            Criteria one = where("name").is(testItem.getName()).and("type").is(testItem.getType().toString());
            if (null != testItem.getItemDescription())
                one.and("itemDescription").is(testItem.getItemDescription());
            if (null != testItem.getTags())
                one.and("tags").is(testItem.getTags());
            itemCriteries[i] = one;
        }

        criteria.orOperator(itemCriteries);
        return criteria;
    }

    @Override
    public List<TestItem> findByHasChildStatus(boolean hasChildren, String launch) {
        Query query = query(where(LAUNCH_REFERENCE).is(launch)).addCriteria(where(HAS_CHILD).is(hasChildren))
                .with(new Sort(Sort.Direction.ASC, START_TIME));
        return mongoTemplate.find(query, TestItem.class);
    }

    @Override
    public List<TestItem> findForSpecifiedSubType(List<String> launchesIds, boolean hasChild,
            StatisticSubType type) {
        String issueField = "statistics.issueCounter."
                + TestItemIssueType.valueOf(type.getTypeRef()).awareStatisticsField() + "." + type.getLocator();
        Query query = query(where(LAUNCH_REFERENCE).in(launchesIds)).addCriteria(where(HAS_CHILD).is(hasChild))
                .addCriteria(where(issueField).exists(true)).with(new Sort(Sort.Direction.ASC, START_TIME));
        return mongoTemplate.find(query, TestItem.class);
    }

    @Override
    public List<TestItem> findTestItemWithIssues(String launchId) {
        Criteria externalIssues = new Criteria().andOperator(where(LAUNCH_REFERENCE).is(launchId),
                where(ISSUE).exists(true));
        Query query = query(externalIssues);
        return mongoTemplate.find(query, TestItem.class);
    }
}