org.sonarqube.tests.upgrade.UpgradeTest.java Source code

Java tutorial

Introduction

Here is the source code for org.sonarqube.tests.upgrade.UpgradeTest.java

Source

/*
 * SonarQube
 * Copyright (C) 2009-2018 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonarqube.tests.upgrade;

import com.codeborne.selenide.Selenide;
import com.codeborne.selenide.WebDriverRunner;
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.OrchestratorBuilder;
import com.sonar.orchestrator.build.MavenBuild;
import com.sonar.orchestrator.container.Server;
import com.sonar.orchestrator.locator.FileLocation;
import com.sonar.orchestrator.version.Version;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Test;
import org.sonarqube.qa.util.SelenideConfig;
import org.sonarqube.ws.Measures;
import org.sonarqube.ws.Measures.Measure;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.client.BaseService;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.PostRequest;
import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.WsClientFactories;
import org.sonarqube.ws.client.WsResponse;
import org.sonarqube.ws.client.measures.ComponentRequest;

import static com.codeborne.selenide.Condition.hasText;
import static com.codeborne.selenide.Selenide.$;
import static java.lang.Integer.parseInt;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;

public class UpgradeTest {

    private static final String PROJECT_KEY = "org.apache.struts:struts-parent";
    private static final String LATEST_JAVA_RELEASE = "LATEST_RELEASE";
    private static final Version DEV_VERSION = Version.create("DEV");

    private Orchestrator orchestrator;

    @After
    public void stop() {
        if (orchestrator != null) {
            orchestrator.stop();
            orchestrator = null;
        }
    }

    @Test
    public void test_upgrade_from_5_6_1() {
        testDatabaseUpgrade(Version.create("5.6.1"));
    }

    private void testDatabaseUpgrade(Version fromVersion) {
        startOldVersionServer(fromVersion, false);
        scanProject();
        int files = countFilesOld(PROJECT_KEY);
        assertThat(files).isGreaterThan(0);
        stopServer();

        startAndUpgradeDevServer();
        verifyAnalysis(files);
        stopServer();
    }

    private void verifyAnalysis(int expectedNumberOfFiles) {
        assertThat(countFilesNew(PROJECT_KEY)).isEqualTo(expectedNumberOfFiles);
        scanProject();
        assertThat(countFilesNew(PROJECT_KEY)).isEqualTo(expectedNumberOfFiles);
        browseWebapp();
    }

    private void checkSystemStatus(Version sqVersion, ServerStatusResponse.Status serverStatus) {
        ServerStatusResponse serverStatusResponse = new ServerStatusCall(orchestrator).callAndWait();

        assertThat(serverStatusResponse.getStatus())
                .describedAs("Server status of version " + sqVersion + " should be " + serverStatus)
                .isEqualTo(serverStatus);
    }

    private void checkUrlsBeforeUpgrade() {
        // These urls should be available when system requires a migration
        checkUrlIsReturningOk("/api/system/status");
        checkUrlIsReturningOk("/api/system/db_migration_status");
        checkUrlIsReturningOk("/api/webservices/list");

        // These urls should not be available when system requires a migration
        checkUrlIsReturningNotFound("/api/issues/search?projectKeys=org.apache.struts%3Astruts-core");
        checkUrlIsReturningNotFound("/api/components/tree?baseComponentKey=org.apache.struts%3Astruts-core");
        checkUrlIsReturningNotFound(
                "/api/measures/component_tree?baseComponentKey=org.apache.struts%3Astruts-core&metricKeys=ncloc,files,violations");
        checkUrlIsReturningNotFound("/api/qualityprofiles/search");

        // These page should all redirect to maintenance page
        checkUrlIsRedirectedToMaintenancePage("/");
        checkUrlIsRedirectedToMaintenancePage("/issues/index");
        checkUrlIsRedirectedToMaintenancePage("/dashboard/index/org.apache.struts:struts-parent");
        checkUrlIsRedirectedToMaintenancePage("/issues");
        checkUrlIsRedirectedToMaintenancePage(
                "/component/index?id=org.apache.struts%3Astruts-core%3Asrc%2Fmain%2Fjava%2Forg%2Fapache%2Fstruts%2Fchain%2Fcommands%2Fgeneric%2FWrappingLookupCommand.java");
        checkUrlIsRedirectedToMaintenancePage("/profiles");
    }

    private void checkUrlsAfterUpgrade() {
        checkUrlIsReturningOk("/api/system/status");
        checkUrlIsReturningOk("/api/system/db_migration_status");
        checkUrlIsReturningOk("/api/webservices/list");
        checkUrlIsReturningOk("/api/l10n/index");

        checkUrlIsReturningOk("/api/issues/search?projectKeys=org.apache.struts%3Astruts-core");
        checkUrlIsReturningOk("/api/components/tree?baseComponentKey=org.apache.struts%3Astruts-core");
        checkUrlIsReturningOk(
                "/api/measures/component_tree?baseComponentKey=org.apache.struts%3Astruts-core&metricKeys=ncloc,files,violations");
        checkUrlIsReturningOk("/api/qualityprofiles/search");
    }

    private void browseWebapp() {
        testUrl("/");
        testUrl("/api/issues/search?projectKeys=org.apache.struts%3Astruts-core");
        testUrl("/api/components/tree?baseComponentKey=org.apache.struts%3Astruts-core");
        testUrl("/api/measures/component_tree?baseComponentKey=org.apache.struts%3Astruts-core&metricKeys=ncloc,files,violations");
        testUrl("/api/qualityprofiles/search");
        testUrl("/issues/index");
        testUrl("/dashboard/index/org.apache.struts:struts-parent");
        testUrl("/issues");
        testUrl("/component/index?id=org.apache.struts%3Astruts-core%3Asrc%2Fmain%2Fjava%2Forg%2Fapache%2Fstruts%2Fchain%2Fcommands%2Fgeneric%2FWrappingLookupCommand.java");
        testUrl("/profiles");
    }

    private void startOldVersionServer(Version sqVersion, boolean keepDatabase) {
        OrchestratorBuilder builder = Orchestrator.builderEnv().setSonarVersion(sqVersion.toString())
                .setOrchestratorProperty("orchestrator.keepDatabase", String.valueOf(keepDatabase))
                .setOrchestratorProperty("javaVersion", "3.14").addPlugin("java")
                .setStartupLogWatcher(log -> log.contains("Process[web] is up"));
        orchestrator = builder.build();
        orchestrator.start();
        initSelenide(orchestrator);
    }

    private void startAndUpgradeDevServer() {
        OrchestratorBuilder builder = Orchestrator.builderEnv()
                .setZipFile(FileLocation
                        .byWildcardMavenFilename(new File("../sonar-application/target"), "sonar*.zip").getFile())
                .setOrchestratorProperty("orchestrator.keepDatabase", "true")
                .setOrchestratorProperty("javaVersion", LATEST_JAVA_RELEASE).addPlugin("java")
                .setStartupLogWatcher(log -> log.contains("Database must be upgraded"));
        orchestrator = builder.build();
        orchestrator.start();
        initSelenide(orchestrator);

        checkSystemStatus(DEV_VERSION, ServerStatusResponse.Status.DB_MIGRATION_NEEDED);
        checkUrlsBeforeUpgrade();
        ServerMigrationResponse serverMigrationResponse = new ServerMigrationCall(orchestrator).callAndWait();
        assertThat(serverMigrationResponse.getStatus())
                .describedAs("Migration status should be MIGRATION_SUCCEEDED")
                .isEqualTo(ServerMigrationResponse.Status.MIGRATION_SUCCEEDED);
        checkSystemStatus(DEV_VERSION, ServerStatusResponse.Status.UP);
        checkUrlsAfterUpgrade();
    }

    private void stopServer() {
        if (orchestrator != null) {
            orchestrator.stop();
        }
    }

    private void scanProject() {
        MavenBuild build = MavenBuild.create(new File("projects/struts-1.3.9-diet/pom.xml"))
                // force version of Maven scanner because recent releases do not support SonarQube versions
                // lower than 5.6.
                .setGoals("clean package", "org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar")
                // exclude pom.xml, otherwise it will be published in SQ 6.3+ and not in previous versions, resulting in a different number of
                // components
                .setProperty("sonar.exclusions", "**/pom.xml").setProperty("sonar.scm.disabled", "true")
                .setProperty("sonar.cpd.cross_project", "true");
        orchestrator.executeBuild(build);
    }

    private int countFilesOld(String key) {
        PostRequest httpRequest = new PostRequest("api/measures/component").setParam("componentKey", key)
                .setParam("metricKeys", singletonList("files")).setMediaType(MediaTypes.PROTOBUF);
        WsResponse response = HttpConnector.newBuilder().url(orchestrator.getServer().getUrl()).build()
                .call(httpRequest);
        Measure measure = BaseService.convert(response, Measures.ComponentWsResponse.parser()).getComponent()
                .getMeasures(0);
        return parseInt(measure.getValue());
    }

    private int countFilesNew(String key) {
        Measure measure = newWsClient(orchestrator).measures()
                .component(new ComponentRequest().setComponent(key).setMetricKeys(singletonList("files")))
                .getComponent().getMeasures(0);
        return parseInt(measure.getValue());
    }

    private void testUrl(String path) {
        HttpURLConnection connection = null;
        try {
            URL url = new URL(orchestrator.getServer().getUrl() + path);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            assertThat(connection.getResponseCode()).as("Fail to load " + path)
                    .isEqualTo(HttpURLConnection.HTTP_OK);

            String content = IOUtils.toString(connection.getInputStream());
            assertThat(content).as("Fail to load " + path).doesNotContain("something went wrong");
            assertThat(content).as("Fail to load " + path)
                    .doesNotContain("The page you were looking for doesn't exist");
            assertThat(content).as("Fail to load " + path).doesNotContain("Unauthorized access");

        } catch (IOException e) {
            throw new IllegalStateException("Error with " + path, e);

        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    private void checkUrlIsReturningOk(String url) {
        newWsClient(orchestrator).wsConnector().call(new GetRequest(url)).failIfNotSuccessful();
    }

    private void checkUrlIsReturningNotFound(String url) {
        WsResponse response = newWsClient(orchestrator).wsConnector().call(new GetRequest(url));
        assertThat(response.code()).isEqualTo(HttpURLConnection.HTTP_NOT_FOUND);
    }

    private void checkUrlIsRedirectedToMaintenancePage(String url) {
        shouldBeRedirectToMaintenance(url);
    }

    private static WsClient newWsClient(Orchestrator orchestrator) {
        Server server = orchestrator.getServer();
        return WsClientFactories.getDefault().newClient(HttpConnector.newBuilder().url(server.getUrl()).build());
    }

    private static void initSelenide(Orchestrator orchestrator) {
        SelenideConfig.configure(orchestrator);
        WebDriverRunner.getWebDriver().manage().deleteAllCookies();
    }

    private void shouldBeRedirectToMaintenance(String relativeUrl) {
        Selenide.open(relativeUrl);
        $("#content").should(hasText("SonarQube is under maintenance"));
    }
}