All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.qameta.allure.ga.GaPlugin Maven / Gradle / Ivy

There is a newer version: 2.30.0
Show newest version
/*
 *  Copyright 2016-2024 Qameta Software Inc
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package io.qameta.allure.ga;

import com.fasterxml.jackson.databind.json.JsonMapper;
import io.qameta.allure.Aggregator2;
import io.qameta.allure.ReportStorage;
import io.qameta.allure.core.Configuration;
import io.qameta.allure.core.LaunchResults;
import io.qameta.allure.entity.ExecutorInfo;
import io.qameta.allure.entity.Label;
import io.qameta.allure.entity.LabelName;
import io.qameta.allure.executor.ExecutorPlugin;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

import static io.qameta.allure.Constants.NO_ANALYTICS;

/**
 * @author charlie (Dmitry Baev).
 */
@SuppressWarnings({"PMD.ExcessiveImports"})
public class GaPlugin implements Aggregator2 {

    private static final Logger LOGGER = LoggerFactory.getLogger(GaPlugin.class);

    private static final String LOCAL = "local";

    private static final String GA_ENDPOINT_FORMAT
            = "https://www.google-analytics.com/mp/collect?measurement_id=%s&api_secret=%s";

    private static final String MEASUREMENT_ID = "G-FVWC4GKEYS";
    private static final String GA_SECRET = "rboZz0HySdmCVIvtydmSTQ";

    private static final String GA_EVENT_NAME = "report_generated";

    @Override
    public void aggregate(final Configuration configuration,
                          final List launchesResults,
                          final ReportStorage storage) {
        if (Objects.nonNull(System.getenv(NO_ANALYTICS))) {
            LOGGER.debug("analytics is disabled");
            return;
        }

        LOGGER.debug("send analytics");
        final GaParameters parameters = new GaParameters()
                .setReportUuid(configuration.getUuid())
                .setAllureVersion(configuration.getVersion())
                .setExecutorType(getExecutorType(launchesResults))
                .setResultsCount(getTestResultsCount(launchesResults))
                .setResultsFormat(getLabelValuesAsString(launchesResults, LabelName.RESULT_FORMAT))
                .setFramework(getLabelValuesAsString(launchesResults, LabelName.FRAMEWORK))
                .setLanguage(getLabelValuesAsString(launchesResults, LabelName.LANGUAGE));

        final String cid = getClientId(launchesResults);

        try {
            CompletableFuture
                    .runAsync(() -> sendStats(cid, parameters))
                    .get(10, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            LOGGER.debug("Could not send analytics within 10 seconds", e);
        }
    }

    protected void sendStats(final String clientId, final GaParameters parameters) {
        final HttpClientBuilder builder = HttpClientBuilder.create();
        try (CloseableHttpClient client = builder.build()) {
            final String uri = String.format(
                    GA_ENDPOINT_FORMAT,
                    MEASUREMENT_ID, GA_SECRET
            );
            final HttpPost post = new HttpPost(uri);
            final String stringBody = new JsonMapper().writeValueAsString(
                    new GaRequest()
                            .setClientId(clientId)
                            .setEvents(Collections.singletonList(new GaEvent()
                                    .setName(GA_EVENT_NAME)
                                    .setParams(parameters)
                            ))
            );
            final StringEntity entity = new StringEntity(
                    stringBody,
                    ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8)
            );
            post.setEntity(entity);
            client.execute(post).close();
            LOGGER.debug("GA done");
        } catch (IOException e) {
            LOGGER.debug("Could not send analytics", e);
        }
    }

    private static String getClientId(final List launchesResults) {
        return ExecutorPlugin.getLatestExecutor(launchesResults)
                .map(ExecutorInfo::getBuildUrl)
                .flatMap(GaPlugin::getHostSafe)
                .map(DigestUtils::sha256Hex)
                .orElseGet(() -> getLocalHostName()
                        .map(DigestUtils::sha256Hex)
                        .orElse(UUID.randomUUID().toString())
                );
    }

    private static Optional getHostSafe(final String url) {
        try {
            return Optional.of(URI.create(url))
                    .map(URI::getHost);
        } catch (Exception e) {
            LOGGER.debug("invalid build url", e);
        }
        return Optional.empty();
    }

    /* package-private */
    static String getExecutorType(final List launchesResults) {
        return ExecutorPlugin.getLatestExecutor(launchesResults)
                .map(ExecutorInfo::getType)
                .map(String::trim)
                .map(String::toLowerCase)
                .orElse(LOCAL);
    }

    private static long getTestResultsCount(final List launchesResults) {
        return launchesResults.stream()
                .map(LaunchResults::getResults)
                .mapToLong(Collection::size)
                .sum();
    }

    private static String getLabelValuesAsString(final List launchesResults,
                                                 final LabelName labelName) {
        final String values = launchesResults.stream()
                .flatMap(results -> results.getResults().stream())
                .flatMap(result -> result.getLabels().stream())
                .filter(label -> labelName.value().equals(label.getName()))
                .map(Label::getValue)
                .distinct()
                .sorted()
                .collect(Collectors.joining(" "))
                .toLowerCase();
        return values.isEmpty() ? "Undefined" : values;
    }

    private static Optional getLocalHostName() {
        try {
            return Optional.ofNullable(InetAddress.getLocalHost().getHostName());
        } catch (UnknownHostException e) {
            LOGGER.debug("Could not get host name", e);
            return Optional.empty();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy