integration.MigrationTest.java Source code

Java tutorial

Introduction

Here is the source code for integration.MigrationTest.java

Source

/*
 * The MIT License
 *
 * Copyright (c) 2017 CloudBees, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

package integration;

import com.cloudbees.hudson.plugins.folder.ChildNameGenerator;
import hudson.model.Job;
import hudson.model.TopLevelItem;
import integration.harness.BasicMultiBranchProjectFactory;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import jenkins.branch.MultiBranchProject;
import jenkins.branch.OrganizationFolder;
import jenkins.scm.impl.mock.MockSCMController;
import jenkins.scm.impl.mock.MockSCMDiscoverBranches;
import jenkins.scm.impl.mock.MockSCMNavigator;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.RestartableJenkinsRule;
import org.jvnet.hudson.test.recipes.LocalData;

import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;

public class MigrationTest {

    private static MockSCMController c;

    @Rule
    public RestartableJenkinsRule r = new RestartableJenkinsRule();

    @BeforeClass
    public static void setupSCM() throws IOException {
        c = MockSCMController.recreate("ee708b58-864e-415c-a8fe-f5e458cda8d9");
        c.createRepository("test.example.com");
        c.createRepository("ireann");
        c.createRepository("???");
        c.createRepository("");
        c.createRepository("Espaa");
        c.createRepository("");
        c.createBranch("test.example.com", "feature: welcome");
        c.createBranch("test.example.com", "feature: browsing/part 1");
        c.createBranch("test.example.com", "feature: browsing/part 2");
        c.createBranch("ireann", "gn/nua");
        c.createBranch("???", "??/");
        c.createBranch("", "?/");
        c.createBranch("Espaa", "caracterstica/nuevo");
        c.createBranch("", "/");
    }

    @AfterClass
    public static void closeSCM() {
        IOUtils.closeQuietly(c);
        c = null;
    }

    /**
     * Checks that data is migrated correctly from 1.x to current version.
     */
    @Test
    @LocalData
    public void nameMangling() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    /**
     * Checks that data migrated from 1.x to 2.0.0 name mangling is still valid when re-migrated to 2.0.2 name mangling
     */
    @Test
    @LocalData
    public void nameMangling_2() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    @Test
    public void createdFromScratch() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                OrganizationFolder foo = r.j.createProject(OrganizationFolder.class, "foo");
                foo.getSCMNavigators().add(new MockSCMNavigator(c, new MockSCMDiscoverBranches()));
                foo.getProjectFactories()
                        .replaceBy(Collections.singletonList(new BasicMultiBranchProjectFactory(null)));
                foo.scheduleBuild2(0).getFuture().get();
                r.j.waitUntilNoActivity();
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    /**
     * Checks that data is migrated correctly from 1.x to current version.
     */
    @Test
    @LocalData
    public void nameMangling_full_reload() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                r.j.jenkins.reload();
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    /**
     * Checks that data migrated from 1.x to 2.0.0 name mangling is still valid when re-migrated to 2.0.2 name mangling
     */
    @Test
    @LocalData
    public void nameMangling_2_full_reload() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                r.j.jenkins.reload();
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    @Test
    public void createdFromScratch_full_reload() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                OrganizationFolder foo = r.j.createProject(OrganizationFolder.class, "foo");
                foo.getSCMNavigators().add(new MockSCMNavigator(c, new MockSCMDiscoverBranches()));
                foo.getProjectFactories()
                        .replaceBy(Collections.singletonList(new BasicMultiBranchProjectFactory(null)));
                foo.scheduleBuild2(0).getFuture().get();
                r.j.waitUntilNoActivity();
                r.j.jenkins.reload();
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    /**
     * Checks that data is migrated correctly from 1.x to current version.
     */
    @Test
    @LocalData
    public void nameMangling_folder_reload() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                OrganizationFolder foo = r.j.jenkins.getItemByFullName("foo", OrganizationFolder.class);
                foo.doReload();
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    /**
     * Checks that data migrated from 1.x to 2.0.0 name mangling is still valid when re-migrated to 2.0.2 name mangling
     */
    @Test
    @LocalData
    public void nameMangling_2_folder_reload() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                OrganizationFolder foo = r.j.jenkins.getItemByFullName("foo", OrganizationFolder.class);
                foo.doReload();
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    @Test
    public void createdFromScratch_folder_reload() throws Exception {
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                OrganizationFolder foo = r.j.createProject(OrganizationFolder.class, "foo");
                foo.getSCMNavigators().add(new MockSCMNavigator(c, new MockSCMDiscoverBranches()));
                foo.getProjectFactories()
                        .replaceBy(Collections.singletonList(new BasicMultiBranchProjectFactory(null)));
                foo.scheduleBuild2(0).getFuture().get();
                r.j.waitUntilNoActivity();
                foo.doReload();
                assertDataMigrated(foo);
            }
        });
        r.addStep(new Statement() {
            @Override
            public void evaluate() throws Throwable {
                TopLevelItem foo = r.j.jenkins.getItem("foo");
                assertDataMigrated(foo);
            }
        });
    }

    private void assertDataMigrated(TopLevelItem foo) throws Exception {
        assertThat(foo, instanceOf(OrganizationFolder.class));
        OrganizationFolder prj = (OrganizationFolder) foo;
        Map<String, MultiBranchProject> byName = new HashMap<>();
        Map<String, MultiBranchProject> byDirName = new HashMap<>();
        Map<String, MultiBranchProject> byDisplayName = new HashMap<>();
        Map<String, Job> jobByName = new HashMap<>();
        Map<String, Job> jobByDirName = new HashMap<>();
        Map<String, Job> jobByDisplayName = new HashMap<>();
        System.out.println("Jobs");
        System.out.println("====");
        System.out.println();
        // Assume NFC
        String espana = "Espaa";
        String espanaMangled = "Espa_f1a.9jabqu";
        String ireland = "ireann";
        String irelandMangled = "0_c9ireann.giuvlt";
        String korea = "";
        String koreaMangled = "0_b3_00_d5_5c_bb_fc_ad_6d.ufdgbs";
        String korea2 = "/";
        String korea2Mangled = "0_d2_b9_c0_c.ps50ht._b8_5c_c6_b4";
        // Assume not windows-1252
        String russia = "???";
        String russiaMangled = "0_04_20_04_3.pei3d7._04_38_04_4f";
        String china = "";
        String chinaMangled = "0_4e_2d_56_fd.m4k0dn";
        for (MultiBranchProject<?, ?> p : prj.getItems()) {
            String dirName = p.getRootDir().getName();
            System.out.printf("%s ==> %s ==> %s == \"%s\"%n", dirName, p.getName(), p.getDisplayName(),
                    asJavaString(p.getDisplayName()));
            byName.put(p.getName(), p);
            if (dirName.equals("Espan_03_03a.eqqe01")) {
                // NFD
                espana = "Espa\u006e\u0303a";
                espanaMangled = "Espan_03_03a.eqqe01";
            }
            if (dirName.equals("Espan_cc_01_92a.po41g5")) {
                // Windows-1252
                espana = "Espan\u00cc\u0192a";
                espanaMangled = "Espan_cc_01_92a.po41g5";
            }
            if (dirName.equals("E_03_01ireann.0qtq11")) {
                // NFD
                ireland = "E\u0301ireann";
                irelandMangled = "E_03_01ireann.0qtq11";
            }
            if (dirName.equals("E_cc_ff_fdireann.k4nq8h")) {
                // Windows-1252
                ireland = "E\u00cc\ufffdireann";
                irelandMangled = "E_cc_ff_fdireann.k4nq8h";
            }
            if (dirName.equals("0_d0_a0_d.co5tjl6h6dbk._d1_ff_fd")) {
                // Windows-1252
                russia = "\u00d0\u00a0\u00d0\u00be\u00d1\ufffd\u00d1\ufffd\u00d0\u00b8\u00d1\ufffd";
                russiaMangled = "0_d0_a0_d.co5tjl6h6dbk._d1_ff_fd";
            }
            if (dirName.equals("0_e4_b8_ad_e5_20_3a_bd.546c3v")) {
                // Windows-1252
                china = "\u00e4\u00b8\u00ad\u00e5\u203a\u00bd";
                chinaMangled = "0_e4_b8_ad_e5_20_3a_bd.546c3v";
            }
            if (dirName.equals("0_11_03_1.3gi5g2rs7pg4._6e_11_a8")) {
                // NFD
                korea = "\u1103\u1162\u1112\u1161\u11ab\u1106\u1175\u11ab\u1100\u116e\u11a8";
                koreaMangled = "0_11_03_1.3gi5g2rs7pg4._6e_11_a8";
            }
            if (dirName.equals("0_e1_20_1.78185nsomvje._20_20_a8")) {
                // Windows-1252
                korea = "\u00e1\u201e\u0192\u00e1\u2026\u00a2\u00e1\u201e\u2019\u00e1\u2026\u00a1\u00e1\u2020\u00ab"
                        + "\u00e1\u201e\u2020\u00e1\u2026\u00b5\u00e1\u2020\u00ab\u00e1\u201e\u20ac\u00e1\u2026\u00ae"
                        + "\u00e1\u2020\u00a8";
                koreaMangled = "0_e1_20_1.78185nsomvje._20_20_a8";
            }
            byDirName.put(dirName, p);
            byDisplayName.put(p.getDisplayName(), p);
            for (Job<?, ?> j : p.getItems()) {
                String jobDirName = prj.getRootDir().getName() + "/" + p.getRootDir().getName() + "/"
                        + j.getRootDir().getName();
                System.out.printf("  %s ==> %s ==> %s == \"%s\" %n", jobDirName, j.getName(), j.getDisplayName(),
                        asJavaString(j.getDisplayName()));
                if (j.getName().equals("0_11_10_1.m479ph0h00p7._6e_11_ab")) {
                    // NFD
                    korea2 = "\u1110\u1173\u11a8\u1109\u1162\u11a8/\u1109\u1162\u1105\u1169\u110b\u116e\u11ab";
                    korea2Mangled = "0_11_10_1.m479ph0h00p7._6e_11_ab";
                }
                jobByName.put(j.getFullName(), j);
                jobByDirName.put(jobDirName, j);
                jobByDisplayName.put(j.getFullDisplayName(), j);
                File nameFile = new File(j.getRootDir(), ChildNameGenerator.CHILD_NAME_FILE);
                assertThat("Exists: " + nameFile, nameFile.isFile(), is(true));
                assertThat("Contents: " + nameFile, FileUtils.readFileToString(nameFile, StandardCharsets.UTF_8),
                        is(j.getName()));
            }
            File nameFile = new File(p.getRootDir(), ChildNameGenerator.CHILD_NAME_FILE);
            assertThat("Exists: " + nameFile, nameFile.isFile(), is(true));
            assertThat("Contents: " + nameFile, FileUtils.readFileToString(nameFile, StandardCharsets.UTF_8),
                    is(p.getName()));
        }
        assertThat("Display Names are repo names", byDisplayName.keySet(),
                containsInAnyOrder("test.example.com", ireland, russia, china, espana, korea));
        assertThat("Directory names have been mangled", byDirName.keySet(),
                containsInAnyOrder("test-example-com.34nhgh", irelandMangled, // ireann
                        russiaMangled, // ???
                        chinaMangled, // 
                        espanaMangled, // Espaa
                        koreaMangled // 
                ));
        assertThat("Folder names have been minimal url path segment pre-encoded", byName.keySet(),
                containsInAnyOrder("test.example.com", ireland, // ireann
                        russia, // ???
                        china, // 
                        espana, // Espaa
                        korea // 
                ));

        assertThat("Display Names are branch names", jobByDisplayName.keySet(),
                containsInAnyOrder("foo  test.example.com  master",
                        "foo  test.example.com  feature: browsing/part 1",
                        "foo  test.example.com  feature: browsing/part 2",
                        "foo  test.example.com  feature: welcome", "foo  " + ireland + "  master",
                        "foo  " + ireland + "  gn/nua", "foo  " + russia + "  master",
                        "foo  " + russia + "  ??/",
                        "foo  " + china + "  master", "foo  " + china + "  ?/",
                        "foo  " + espana + "  master", "foo  " + espana + "  caracterstica/nuevo",
                        "foo  " + korea + "  master", "foo  " + korea + "  " + korea2));
        assertThat("Job directory names have been mangled", jobByDirName.keySet(), containsInAnyOrder(
                "foo/test-example-com.34nhgh/master",
                "foo/test-example-com.34nhgh/feature_3a-b.jk8rfi.wsing-part-1",
                "foo/test-example-com.34nhgh/feature_3a-b.m8lpav.wsing-part-2",
                "foo/test-example-com.34nhgh/feature_3a-welcome.9dhrtb", "foo/" + irelandMangled + "/master",
                "foo/" + irelandMangled + "/gn_e9-nua.updi5h", "foo/" + russiaMangled + "/master",
                "foo/" + russiaMangled + "/0_04_3e_0.n168ksdsksof._4b_04_39", "foo/" + chinaMangled + "/master",
                "foo/" + chinaMangled + "/0_72_79_5f_81-_65_b0.nt1m48", "foo/" + espanaMangled + "/master",
                "foo/" + espanaMangled + "/caracter_edstica-nuevo.h5da9f", "foo/" + koreaMangled + "/master",
                "foo/" + koreaMangled + "/" + korea2Mangled));

        assertThat("Job names have been minimal url path segment pre-encoded", jobByName.keySet(),
                containsInAnyOrder("foo/test.example.com/master", "foo/test.example.com/feature: browsing%2Fpart 1",
                        "foo/test.example.com/feature: browsing%2Fpart 2", "foo/test.example.com/feature: welcome",
                        "foo/" + ireland + "/master", "foo/" + ireland + "/gn%2Fnua", "foo/" + russia + "/master",
                        "foo/" + russia + "/??%2F", "foo/" + china + "/master",
                        "foo/" + china + "/?%2F", "foo/" + espana + "/master",
                        "foo/" + espana + "/caracterstica%2Fnuevo", "foo/" + korea + "/master",
                        "foo/" + korea + "/%2F"));

        assertThat(prj.getItemByProjectName(ireland), notNullValue());
        assertThat(prj.getItemByProjectName(ireland).getItemByBranchName("gn/nua"), notNullValue());
    }

    private CharSequence asJavaString(String rawString) {
        StringBuilder b = new StringBuilder();
        for (char c : rawString.toCharArray()) {
            if (c >= 32 && c < 128) {
                b.append(c);
            } else {
                b.append("\\u").append(StringUtils.leftPad(Integer.toHexString(c & 0xffff), 4, '0'));
            }
        }
        return b;
    }
}