com.googlesource.gerrit.plugins.supermanifest.JiriSuperManifestIT.java Source code

Java tutorial

Introduction

Here is the source code for com.googlesource.gerrit.plugins.supermanifest.JiriSuperManifestIT.java

Source

// Copyright (C) 2016 The Android Open Source Project
//
// 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 com.googlesource.gerrit.plugins.supermanifest;

import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.PushOneCommit.Result;
import com.google.gerrit.acceptance.TestPlugin;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.extensions.api.projects.BranchApi;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.Project.NameKey;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.inject.Inject;
import java.net.URI;
import java.util.Arrays;
import org.apache.commons.lang.RandomStringUtils;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.BlobBasedConfig;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;

@TestPlugin(name = "supermanifest", sysModule = "com.googlesource.gerrit.plugins.supermanifest.SuperManifestModule")
public class JiriSuperManifestIT extends LightweightPluginDaemonTest {
    NameKey[] testRepoKeys;

    @Inject
    private ProjectOperations projectOperations;

    void setupTestRepos(String prefix) throws Exception {
        testRepoKeys = new NameKey[2];
        for (int i = 0; i < 2; i++) {
            testRepoKeys[i] = projectOperations.newProject()
                    .name(RandomStringUtils.randomAlphabetic(8) + prefix + i).create();

            TestRepository<InMemoryRepository> repo = cloneProject(testRepoKeys[i], admin);

            PushOneCommit push = pushFactory.create(admin.getIdent(), repo, "Subject", "file" + i, "file");
            push.to("refs/heads/master").assertOkStatus();
        }
    }

    void pushConfig(String config) throws Exception {
        // This will trigger a configuration reload.
        TestRepository<InMemoryRepository> allProjectRepo = cloneProject(allProjects, admin);
        GitUtil.fetch(allProjectRepo, RefNames.REFS_CONFIG + ":config");
        allProjectRepo.reset("config");
        PushOneCommit push = pushFactory.create(admin.getIdent(), allProjectRepo, "Subject", "supermanifest.config",
                config);
        PushOneCommit.Result res = push.to("refs/meta/config");
        res.assertOkStatus();
    }

    @Test
    public void basicFunctionalityWorks() throws Exception {
        setupTestRepos("project");

        // Make sure the manifest exists so the configuration loads successfully.
        NameKey manifestKey = projectOperations.newProject().name(name("manifest")).create();
        TestRepository<InMemoryRepository> manifestRepo = cloneProject(manifestKey, admin);

        NameKey superKey = projectOperations.newProject().name(name("superproject")).create();
        cloneProject(superKey, admin);

        pushConfig("[superproject \"" + superKey.get() + ":refs/heads/destbranch\"]\n" + "  srcRepo = "
                + manifestKey.get() + "\n" + "  srcRef = refs/heads/srcbranch\n" + "  srcPath = default\n"
                + "  toolType = jiri\n");

        // XML change will trigger commit to superproject.
        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "<project name=\"" + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get()
                + testRepoKeys[0].get() + "\" path=\"project1\" />\n" + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/srcbranch")
                .assertOkStatus();

        BranchApi branch = gApi.projects().name(superKey.get()).branch("refs/heads/destbranch");
        assertThat(branch.file("project1").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        try {
            branch.file("project2");
            fail("wanted exception");
        } catch (ResourceNotFoundException e) {
            // all fine.
        }

        xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n" + "  <project name=\""
                + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get() + testRepoKeys[0].get()
                + "\" path=\"project1\" />\n" + "  <project name=\"" + testRepoKeys[1].get() + "\" remote=\""
                + canonicalWebUrl.get() + testRepoKeys[1].get() + "\" path=\"project2\" />\n"
                + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/srcbranch")
                .assertOkStatus();

        branch = gApi.projects().name(superKey.get()).branch("refs/heads/destbranch");
        assertThat(branch.file("project2").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");

        // Make sure config change gets picked up.
        pushConfig("[superproject \"" + superKey.get() + ":refs/heads/other\"]\n" + "  srcRepo = "
                + manifestKey.get() + "\n" + "  srcRef = refs/heads/srcbranch\n" + "  srcPath = default\n"
                + "  toolType = jiri\n");

        // Push another XML change; this should trigger a commit using the new config.
        xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n" + "  <project name=\""
                + testRepoKeys[1].get() + "\" remote=\"" + canonicalWebUrl.get() + testRepoKeys[1].get()
                + "\" path=\"project3\" />\n" + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/srcbranch")
                .assertOkStatus();

        branch = gApi.projects().name(superKey.get()).branch("refs/heads/other");
        assertThat(branch.file("project3").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
    }

    @Test
    public void ImportTagWorks() throws Exception {
        setupTestRepos("project");

        // Make sure the manifest exists so the configuration loads successfully.
        NameKey manifest1Key = projectOperations.newProject().name(name("manifest1")).create();
        TestRepository<InMemoryRepository> manifest1Repo = cloneProject(manifest1Key, admin);

        NameKey manifest2Key = projectOperations.newProject().name(name("manifest2")).create();
        TestRepository<InMemoryRepository> manifest2Repo = cloneProject(manifest2Key, admin);

        NameKey superKey = projectOperations.newProject().name(name("superproject")).create();
        cloneProject(superKey, admin);

        pushConfig("[superproject \"" + superKey.get() + ":refs/heads/destbranch\"]\n" + "  srcRepo = "
                + manifest1Key.get() + "\n" + "  srcRef = refs/heads/srcbranch\n" + "  srcPath = default\n"
                + "  toolType = jiri\n");

        // XML change will trigger commit to superproject.
        String xml1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<imports>\n" + "<import name=\""
                + manifest2Key.get() + "\" manifest=\"default\" remote=\"" + canonicalWebUrl.get()
                + manifest2Key.get() + "\" />\n</imports>" + "<projects>\n" + "<project name=\""
                + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get() + testRepoKeys[0].get()
                + "\" path=\"project1\" />\n" + "</projects>\n</manifest>\n";

        String xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "<project name=\"" + manifest2Key.get() + "\" remote=\"" + canonicalWebUrl.get()
                + manifest2Key.get() + "\" path=\"manifest2\" />\n" + "</projects>\n</manifest>\n";
        pushFactory.create(admin.getIdent(), manifest2Repo, "Subject", "default", xml2).to("refs/heads/master")
                .assertOkStatus();
        pushFactory.create(admin.getIdent(), manifest1Repo, "Subject", "default", xml1).to("refs/heads/srcbranch")
                .assertOkStatus();

        BranchApi branch = gApi.projects().name(superKey.get()).branch("refs/heads/destbranch");
        assertThat(branch.file("project1").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        assertThat(branch.file("manifest2").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
    }

    @Test
    public void ImportTagWithRevisionWorks() throws Exception {
        setupTestRepos("project");

        // Make sure the manifest exists so the configuration loads successfully.
        NameKey manifest1Key = projectOperations.newProject().name(name("manifest1")).create();
        TestRepository<InMemoryRepository> manifest1Repo = cloneProject(manifest1Key, admin);

        NameKey manifest2Key = projectOperations.newProject().name(name("manifest2")).create();
        TestRepository<InMemoryRepository> manifest2Repo = cloneProject(manifest2Key, admin);

        NameKey superKey = projectOperations.newProject().name(name("superproject")).create();
        cloneProject(superKey, admin);

        pushConfig("[superproject \"" + superKey.get() + ":refs/heads/destbranch\"]\n" + "  srcRepo = "
                + manifest1Key.get() + "\n" + "  srcRef = refs/heads/srcbranch\n" + "  srcPath = default\n"
                + "  toolType = jiri\n");

        String xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "<project name=\"" + manifest2Key.get() + "\" remote=\"" + canonicalWebUrl.get()
                + manifest2Key.get() + "\" path=\"manifest2\" />\n" + "</projects>\n</manifest>\n";
        Result c = pushFactory.create(admin.getIdent(), manifest2Repo, "Subject", "default", xml2)
                .to("refs/heads/master");
        c.assertOkStatus();
        RevCommit commit = c.getCommit();

        // Add new project, that should not be imported
        xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n" + "<project name=\""
                + manifest2Key.get() + "\" remote=\"" + canonicalWebUrl.get() + manifest2Key.get()
                + "\" path=\"manifest2\" />\n" + "<project name=\"" + testRepoKeys[1].get() + "\" remote=\""
                + canonicalWebUrl.get() + testRepoKeys[1].get() + "\" path=\"project2\" />\n"
                + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifest2Repo, "Subject", "default", xml2).to("refs/heads/master")
                .assertOkStatus();

        // XML change will trigger commit to superproject.
        String xml1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<imports>\n" + "<import name=\""
                + manifest2Key.get() + "\" manifest=\"default\" remote=\"" + canonicalWebUrl.get()
                + manifest2Key.get() + "\" revision=\"" + commit.name() + "\"/>\n</imports>" + "<projects>\n"
                + "<project name=\"" + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get()
                + testRepoKeys[0].get() + "\" path=\"project1\" />\n" + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifest1Repo, "Subject", "default", xml1).to("refs/heads/srcbranch")
                .assertOkStatus();

        BranchApi branch = gApi.projects().name(superKey.get()).branch("refs/heads/destbranch");
        assertThat(branch.file("project1").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        assertThat(branch.file("manifest2").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        assertThat(branch.file("manifest2").asString()).contains(commit.name());
        try {
            branch.file("project2");
            fail("wanted exception");
        } catch (ResourceNotFoundException e) {
            // all fine.
        }
    }

    @Test
    public void ImportTagWithRemoteBranchWorks() throws Exception {
        setupTestRepos("project");

        // Make sure the manifest exists so the configuration loads successfully.
        NameKey manifest1Key = projectOperations.newProject().name(name("manifest1")).create();
        TestRepository<InMemoryRepository> manifest1Repo = cloneProject(manifest1Key, admin);

        NameKey manifest2Key = projectOperations.newProject().name(name("manifest2")).create();
        TestRepository<InMemoryRepository> manifest2Repo = cloneProject(manifest2Key, admin);

        NameKey superKey = projectOperations.newProject().name(name("superproject")).create();
        cloneProject(superKey, admin);

        pushConfig("[superproject \"" + superKey.get() + ":refs/heads/destbranch\"]\n" + "  srcRepo = "
                + manifest1Key.get() + "\n" + "  srcRef = refs/heads/srcbranch\n" + "  srcPath = default\n"
                + "  toolType = jiri\n");

        String xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "<project name=\"" + manifest2Key.get() + "\" remote=\"" + canonicalWebUrl.get()
                + manifest2Key.get() + "\" path=\"manifest2\" />\n" + "</projects>\n</manifest>\n";
        pushFactory.create(admin.getIdent(), manifest2Repo, "Subject", "default", xml2).to("refs/heads/b1")
                .assertOkStatus();

        // Add new project, that should not be imported
        xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n" + "<project name=\""
                + manifest2Key.get() + "\" remote=\"" + canonicalWebUrl.get() + manifest2Key.get()
                + "\" path=\"manifest2\" />\n" + "<project name=\"" + testRepoKeys[1].get() + "\" remote=\""
                + canonicalWebUrl.get() + testRepoKeys[1].get() + "\" path=\"project2\" />\n"
                + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifest2Repo, "Subject", "default", xml2).to("refs/heads/master")
                .assertOkStatus();

        // XML change will trigger commit to superproject.
        String xml1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<imports>\n" + "<import name=\""
                + manifest2Key.get() + "\" manifest=\"default\" remote=\"" + canonicalWebUrl.get()
                + manifest2Key.get() + "\" remotebranch=\"b1\" />\n</imports>" + "<projects>\n" + "<project name=\""
                + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get() + testRepoKeys[0].get()
                + "\" path=\"project1\" />\n" + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifest1Repo, "Subject", "default", xml1).to("refs/heads/srcbranch")
                .assertOkStatus();

        BranchApi branch = gApi.projects().name(superKey.get()).branch("refs/heads/destbranch");
        assertThat(branch.file("project1").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        assertThat(branch.file("manifest2").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        try {
            branch.file("project2");
            fail("wanted exception");
        } catch (ResourceNotFoundException e) {
            // all fine.
        }
    }

    private void outer() throws Exception {
        inner();
    }

    private void inner() {
        throw new IllegalStateException();
    }

    private void innerTest() throws Exception {
        try {
            outer();
            fail("should throw");
        } catch (IllegalStateException e) {
            StackTraceElement[] trimmed = SuperManifestRefUpdatedListener.trimStack(e.getStackTrace(),
                    Thread.currentThread().getStackTrace()[1]);
            String str = Arrays.toString(trimmed);
            assertThat(str).doesNotContain("trimStackTrace");
            assertThat(str).contains("innerTest");
        }
    }

    @Test
    public void trimStackTrace() throws Exception {
        innerTest();
    }

    @Test
    public void wildcardDestBranchWorks() throws Exception {
        setupTestRepos("project");

        // Make sure the manifest exists so the configuration loads successfully.
        NameKey manifestKey = projectOperations.newProject().name(name("manifest")).create();
        TestRepository<InMemoryRepository> manifestRepo = cloneProject(manifestKey, admin);

        NameKey superKey = projectOperations.newProject().name(name("superproject")).create();
        cloneProject(superKey, admin);

        pushConfig("[superproject \"" + superKey.get() + ":refs/heads/*\"]\n" + "  srcRepo = " + manifestKey.get()
                + "\n" + "  srcRef = blablabla\n" + "  srcPath = default\n" + "  toolType = jiri\n");

        // XML change will trigger commit to superproject.
        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "  <project name=\"" + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get()
                + testRepoKeys[0].get() + "\" path=\"project1\" />\n" + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/src1")
                .assertOkStatus();

        xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n" + "  <project name=\""
                + testRepoKeys[1].get() + "\" remote=\"" + canonicalWebUrl.get() + testRepoKeys[1].get()
                + "\" path=\"project2\" />\n" + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/src2")
                .assertOkStatus();

        BranchApi branch1 = gApi.projects().name(superKey.get()).branch("refs/heads/src1");
        assertThat(branch1.file("project1").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        try {
            branch1.file("project2");
            fail("wanted exception");
        } catch (ResourceNotFoundException e) {
            // all fine.
        }

        BranchApi branch2 = gApi.projects().name(superKey.get()).branch("refs/heads/src2");
        assertThat(branch2.file("project2").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        try {
            branch2.file("project1");
            fail("wanted exception");
        } catch (ResourceNotFoundException e) {
            // all fine.
        }
    }

    @Test
    public void relativeFetch() throws Exception {
        // Test that first party gerrit repos are represented by relative URLs in supermanifest and
        // external repos by their absolute URLs.
        setupTestRepos("platform/project");

        String realPrefix = testRepoKeys[0].get().split("/")[0];

        Project.NameKey manifestKey = projectOperations.newProject().name(name(realPrefix + "/manifest")).create();
        TestRepository<InMemoryRepository> manifestRepo = cloneProject(manifestKey, admin);

        Project.NameKey superKey = projectOperations.newProject().name(name("superproject")).create();
        pushConfig("[superproject \"" + superKey.get() + ":refs/heads/destbranch\"]\n" + "  srcRepo = "
                + manifestKey.get() + "\n" + "  srcRef = refs/heads/srcbranch\n" + "  srcPath = default\n"
                + "  toolType = jiri\n");

        // XML change will trigger commit to superproject.
        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "<project name=\"" + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get()
                + testRepoKeys[0].get() + "\" path=\"project1\" />\n" + "<project name=\"external\""
                + " remote=\"https://external/repo\"" + " revision=\"c438d02cdf08a08fe29550cb11cb6ae8190919f1\""
                + " path=\"project2\" />\n" + "</projects>\n</manifest>\n";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/srcbranch")
                .assertOkStatus();

        BranchApi branch = gApi.projects().name(superKey.get()).branch("refs/heads/destbranch");
        assertThat(branch.file("project1").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
        assertThat(branch.file("project2").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");

        Config base = new Config();
        BlobBasedConfig cfg = new BlobBasedConfig(base, branch.file(".gitmodules").asString().getBytes(UTF_8));

        String subUrl = cfg.getString("submodule", "project1", "url");

        // URL is valid.
        URI.create(subUrl);

        // The suburl must be interpreted as relative to the parent project as a directory, i.e.
        // to go from superproject/ to platform/project0, you have to do ../platform/project0

        // URL is clean.
        assertThat(subUrl).isEqualTo("../" + realPrefix + "/project0");

        subUrl = cfg.getString("submodule", "project2", "url");

        // URL is valid.
        URI.create(subUrl);

        // The suburl must be absolute as this is external repo

        assertThat(subUrl).isEqualTo("https://external/repo");
    }

    @Test
    public void manifestIncludesOtherManifest() throws Exception {
        setupTestRepos("project");

        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "<project name=\"" + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get()
                + testRepoKeys[0].get() + "\" path=\"project1\" />\n" + "</projects>\n</manifest>\n";

        NameKey manifestKey = projectOperations.newProject().name(name("manifest")).create();
        TestRepository<InMemoryRepository> manifestRepo = cloneProject(manifestKey, admin);
        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/master")
                .assertOkStatus();

        String superXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<manifest>\n<imports>\n"
                + "  <localimport file=\"default\"/>" + "</imports>\n</manifest>";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "super", superXml).to("refs/heads/master")
                .assertOkStatus();

        NameKey superKey = projectOperations.newProject().name(name("superproject")).create();
        cloneProject(superKey, admin);

        pushConfig(
                "[superproject \"" + superKey.get() + ":refs/heads/master\"]\n" + "  srcRepo = " + manifestKey.get()
                        + "\n" + "  srcRef = refs/heads/master\n" + "  srcPath = super\n" + "  toolType = jiri\n");

        // Push a change to the source branch. We intentionally change the included XML file
        // (rather than the one mentioned in srcPath), to double check that we don't try to be too
        // smart about eluding nops.
        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml + " ").to("refs/heads/master")
                .assertOkStatus();

        BranchApi branch = gApi.projects().name(superKey.get()).branch("refs/heads/master");
        assertThat(branch.file("project1").getContentType()).isEqualTo("x-git/gitlink; charset=UTF-8");
    }

    @Test
    public void remoteImportFails() throws Exception {
        setupTestRepos("project");

        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<manifest>\n<projects>\n"
                + "<project name=\"" + testRepoKeys[0].get() + "\" remote=\"" + canonicalWebUrl.get()
                + testRepoKeys[0].get() + "\" path=\"project1\" />\n" + "</projects>\n</manifest>\n";

        NameKey manifestKey = projectOperations.newProject().name(name("manifest")).create();
        NameKey superKey = projectOperations.newProject().name(name("superproject")).create();

        cloneProject(superKey, admin);

        pushConfig(
                "[superproject \"" + superKey.get() + ":refs/heads/master\"]\n" + "  srcRepo = " + manifestKey.get()
                        + "\n" + "  srcRef = refs/heads/master\n" + "  srcPath = super\n" + "  toolType = jiri\n");
        TestRepository<InMemoryRepository> manifestRepo = cloneProject(manifestKey, admin);
        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "default", xml).to("refs/heads/master")
                .assertOkStatus();

        String superXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<manifest>\n<imports>\n"
                + "<import manifest=\"" + manifestKey.get() + "\" name=\"default\" remote=\""
                + canonicalWebUrl.get() + manifestKey.get() + "\"/>" + "</imports>\n</manifest>";

        pushFactory.create(admin.getIdent(), manifestRepo, "Subject", "super", superXml).to("refs/heads/master")
                .assertOkStatus();

        BranchApi branch = gApi.projects().name(superKey.get()).branch("refs/heads/master");
        try {
            branch.file("project1");
            fail("wanted exception");
        } catch (ResourceNotFoundException e) {
            // all fine.
        }
    }

    /*
     * Copied test from https://github.com/eclipse/jgit/blob/e9fb111182b55cc82c530d82f13176c7a85cd958/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java#L1105
     */
    void testRelative(String a, String b, String want) throws Exception {
        String got = JiriUpdater.relativize(URI.create(a), URI.create(b)).toString();

        if (!got.equals(want)) {
            fail(String.format("relative('%s', '%s') = '%s', want '%s'", a, b, got, want));
        }
    }

    @Test
    public void relative() throws Exception {
        testRelative("a/b/", "a/", "../");
        // Normalization:
        testRelative("a/p/..//b/", "a/", "../");
        testRelative("a/b", "a/", "");
        testRelative("a/", "a/b/", "b/");
        testRelative("a/", "a/b", "b");
        testRelative("/a/b/c", "/b/c", "../../b/c");
        testRelative("/abc", "bcd", "bcd");
        testRelative("abc", "def", "def");
        testRelative("abc", "/bcd", "/bcd");
        testRelative("http://a", "a/b", "a/b");
        testRelative("http://base.com/a/", "http://child.com/a/b", "http://child.com/a/b");
    }
}