xref: /OpenGrok/opengrok-indexer/src/test/java/org/opengrok/indexer/index/IndexerRepoTest.java (revision eecd4f60f3a13ea423e84d9a403830200ce60b9a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2017, 2019, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.indexer.index;
25 
26 import java.io.File;
27 
28 import java.io.IOException;
29 import java.net.URISyntaxException;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.util.Arrays;
34 import java.util.HashSet;
35 import java.util.List;
36 
37 import static org.junit.jupiter.api.Assertions.assertEquals;
38 import static org.junit.jupiter.api.Assertions.assertNotNull;
39 import static org.junit.jupiter.api.Assertions.assertNull;
40 import static org.junit.jupiter.api.Assertions.assertTrue;
41 import static org.opengrok.indexer.condition.RepositoryInstalled.Type.MERCURIAL;
42 
43 import org.junit.jupiter.api.AfterEach;
44 import org.junit.jupiter.api.BeforeEach;
45 import org.junit.jupiter.api.Test;
46 import org.junit.jupiter.params.ParameterizedTest;
47 import org.junit.jupiter.params.provider.ValueSource;
48 import org.opengrok.indexer.condition.EnabledForRepository;
49 import org.opengrok.indexer.configuration.Project;
50 import org.opengrok.indexer.configuration.RuntimeEnvironment;
51 import org.opengrok.indexer.history.HistoryException;
52 import org.opengrok.indexer.history.HistoryGuru;
53 import org.opengrok.indexer.history.MercurialRepositoryTest;
54 import org.opengrok.indexer.history.RepositoryInfo;
55 import org.opengrok.indexer.util.TestRepository;
56 import org.opengrok.indexer.util.IOUtils;
57 
58 /**
59  * Test indexer w.r.t. repositories.
60  * @author Vladimir Kotal
61  */
62 class IndexerRepoTest {
63 
64     private TestRepository repository;
65 
66     @BeforeEach
setUp()67     public void setUp() throws IOException, URISyntaxException {
68         repository = new TestRepository();
69         // For these tests we need Mercurial repository with renamed files.
70         repository.create(HistoryGuru.class.getResource("/repositories"));
71     }
72 
73     @AfterEach
tearDown()74     public void tearDown() {
75         repository.destroy();
76     }
77 
78     @EnabledForRepository(MERCURIAL)
79     @ParameterizedTest
80     @ValueSource(booleans = {false, true})
testPerProjectHistory(boolean globalOn)81     void testPerProjectHistory(boolean globalOn) throws IndexerException, IOException, HistoryException {
82         RuntimeEnvironment env = RuntimeEnvironment.getInstance();
83 
84         // Make sure we start from scratch.
85         Path dataRoot = Files.createTempDirectory("dataForPerProjectHistoryTest");
86         env.setDataRoot(dataRoot.toString());
87         env.setProjectsEnabled(true);
88         env.setHistoryEnabled(globalOn);
89 
90         // The projects have to be added first so that prepareIndexer() can use their configuration.
91         Project proj = new Project("mercurial", "/mercurial");
92         proj.setHistoryEnabled(!globalOn);
93         env.getProjects().clear();
94         env.getProjects().put("mercurial", proj);
95         proj = new Project("git", "/git");
96         env.getProjects().put("git", proj);
97 
98         HistoryGuru.getInstance().clear();
99         Indexer.getInstance().prepareIndexer(
100                 env,
101                 true, // search for repositories
102                 true, // scan and add projects
103                 false, // don't create dictionary
104                 null, // subFiles - not needed since we don't list files
105                 null); // repositories - not needed when not refreshing history
106         env.generateProjectRepositoriesMap();
107 
108         // The repositories of the git project should follow the global history setting.
109         File repoRoot = new File(env.getSourceRootFile(), "git");
110         File fileInRepo = new File(repoRoot, "main.c");
111         assertTrue(fileInRepo.exists());
112         if (globalOn) {
113             assertNotNull(HistoryGuru.getInstance().getHistory(fileInRepo));
114         } else {
115             assertNull(HistoryGuru.getInstance().getHistory(fileInRepo));
116         }
117 
118         // The repositories of the mercurial project should be opposite to the global history setting.
119         repoRoot = new File(env.getSourceRootFile(), "mercurial");
120         fileInRepo = new File(repoRoot, "main.c");
121         assertTrue(fileInRepo.exists());
122         if (globalOn) {
123             assertNull(HistoryGuru.getInstance().getHistory(fileInRepo));
124         } else {
125             assertNotNull(HistoryGuru.getInstance().getHistory(fileInRepo));
126         }
127 
128         IOUtils.removeRecursive(dataRoot);
129     }
130 
131     /**
132      * Test that symlinked directories from source root get their relative
133      * path set correctly in RepositoryInfo objects.
134      */
135     @EnabledForRepository(MERCURIAL)
136     @Test
testSymlinks()137     void testSymlinks() throws IndexerException, IOException {
138 
139         final String SYMLINK = "symlink";
140         RuntimeEnvironment env = RuntimeEnvironment.getInstance();
141 
142         // Set source root to pristine directory so that there is only one
143         // repository to deal with (which makes this faster and easier to write)
144         // and clone the mercurial repository outside of the source root.
145         Path realSource = Files.createTempDirectory("real");
146         Path sourceRoot = Files.createTempDirectory("src");
147         MercurialRepositoryTest.runHgCommand(sourceRoot.toFile(),
148                 "clone", repository.getSourceRoot() + File.separator + "mercurial",
149                 realSource.toString());
150 
151         // Create symlink from source root to the real repository.
152         String symlinkPath = sourceRoot.toString() + File.separator + SYMLINK;
153         Files.createSymbolicLink(Paths.get(symlinkPath), realSource);
154 
155         // Use alternative source root.
156         env.setSourceRoot(sourceRoot.toString());
157         // Need to have history cache enabled in order to perform scan of repositories.
158         env.setHistoryEnabled(true);
159         // Normally the Indexer would add the symlink automatically.
160         env.setAllowedSymlinks(new HashSet<>(Arrays.asList(symlinkPath)));
161 
162         // Do a rescan of the projects, and only that (we don't care about
163         // the other aspects of indexing in this test case).
164         Indexer.getInstance().prepareIndexer(
165                 env,
166                 true, // search for repositories
167                 true, // scan and add projects
168                 false, // don't create dictionary
169                 null, // subFiles - not needed since we don't list files
170                 null); // repositories - not needed when not refreshing history
171 
172         // Check the repository paths.
173         List<RepositoryInfo> repos = env.getRepositories();
174         assertEquals(repos.size(), 1);
175         RepositoryInfo repo = repos.get(0);
176         assertEquals(File.separator + SYMLINK, repo.getDirectoryNameRelative());
177         String epath = sourceRoot.toString() + File.separator + SYMLINK;
178         String apath = repo.getDirectoryName();
179         assertTrue(epath.equals(apath) || apath.equals("/private" + epath),
180                 "Should match (with macOS leeway):\n" + epath + "\nv.\n" + apath);
181 
182         // Check that history exists for a file in the repository.
183         File repoRoot = new File(env.getSourceRootFile(), SYMLINK);
184         File fileInRepo = new File(repoRoot, "main.c");
185         assertTrue(fileInRepo.exists());
186         assertTrue(HistoryGuru.getInstance().hasHistory(fileInRepo));
187         assertTrue(HistoryGuru.getInstance().hasCacheForFile(fileInRepo));
188 
189         // cleanup
190         IOUtils.removeRecursive(realSource);
191         IOUtils.removeRecursive(sourceRoot);
192     }
193 }
194