Skip to content

Commit d186ae6

Browse files
committed
fall back to the default temporary directory for ctags check
fixes #4574
1 parent 785896c commit d186ae6

File tree

4 files changed

+45
-14
lines changed

4 files changed

+45
-14
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/RuntimeEnvironment.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ public synchronized boolean validateUniversalCtags() {
711711
ctagsLanguages.addAll(languages);
712712
}
713713

714-
ctagsFound = CtagsUtil.validate(ctagsBinary);
714+
ctagsFound = CtagsUtil.isValid(ctagsBinary);
715715
}
716716

717717
if (ctagsFound) {

opengrok-indexer/src/main/java/org/opengrok/indexer/util/CtagsUtil.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import org.apache.commons.lang3.SystemUtils;
2727
import org.jetbrains.annotations.Nullable;
28+
import org.jetbrains.annotations.VisibleForTesting;
2829
import org.opengrok.indexer.analysis.Ctags;
2930
import org.opengrok.indexer.analysis.Definitions;
3031
import org.opengrok.indexer.configuration.RuntimeEnvironment;
@@ -60,29 +61,33 @@ private CtagsUtil() {
6061

6162
/**
6263
* Check that {@code ctags} program exists and is working.
63-
* @param ctagsBinary name of the ctags program or path
64+
* @param ctagsBinary name of the {@code ctags} program or path
6465
* @return true if the program works, false otherwise
6566
*/
66-
public static boolean validate(String ctagsBinary) {
67+
public static boolean isValid(String ctagsBinary) {
6768
if (!isUniversalCtags(ctagsBinary)) {
6869
return false;
6970
}
7071

71-
return canProcessFiles(RuntimeEnvironment.getInstance().getSourceRootFile());
72+
// The source root can be read-only. In such case, fall back to the default
73+
// temporary directory as a second-best choice how to test that ctags is working.
74+
return (canProcessFiles(RuntimeEnvironment.getInstance().getSourceRootFile()) ||
75+
canProcessFiles(new File(System.getProperty("java.io.tmpdir"))));
7276
}
7377

7478
/**
75-
* Run ctags program on a known temporary file to be created under given path and see if it was possible
76-
* to get some symbols.
79+
* Run {@code ctags} program on a known temporary file to be created under given path
80+
* and see if it was possible to get some symbols.
7781
* @param baseDir directory to use for storing the temporary file
7882
* @return true if at least one symbol was found, false otherwise
7983
*/
80-
private static boolean canProcessFiles(File baseDir) {
84+
@VisibleForTesting
85+
static boolean canProcessFiles(File baseDir) {
8186
Path inputPath;
8287
try {
8388
inputPath = File.createTempFile("ctagsValidation", ".c", baseDir).toPath();
8489
} catch (IOException e) {
85-
LOGGER.log(Level.WARNING, "cannot create temporary file in ''{0}''", baseDir);
90+
LOGGER.log(Level.WARNING, String.format("cannot create temporary file in '%s'", baseDir), e);
8691
return false;
8792
}
8893
final String resourceFileName = "sample.c";

opengrok-indexer/src/test/java/org/opengrok/indexer/util/CtagsUtilTest.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
*/
1919

2020
/*
21-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
21+
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
2222
* Copyright (c) 2019, Chris Fraire <cfraire@me.com>.
2323
*/
2424
package org.opengrok.indexer.util;
2525

2626
import org.junit.jupiter.api.Test;
27+
import org.mockito.MockedStatic;
28+
import org.mockito.Mockito;
2729
import org.opengrok.indexer.configuration.RuntimeEnvironment;
2830

2931
import java.io.IOException;
@@ -35,6 +37,9 @@
3537
import static org.junit.jupiter.api.Assertions.assertFalse;
3638
import static org.junit.jupiter.api.Assertions.assertNotNull;
3739
import static org.junit.jupiter.api.Assertions.assertTrue;
40+
import static org.mockito.ArgumentMatchers.eq;
41+
import static org.mockito.Mockito.mockStatic;
42+
import static org.mockito.Mockito.times;
3843

3944
/**
4045
* Represents a container for tests of {@link CtagsUtil}.
@@ -51,19 +56,40 @@ void getLanguages() {
5156
}
5257

5358
@Test
54-
void validate() throws IOException {
59+
void testIsValid() throws IOException {
5560
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
5661
Path tmpSourceRoot = Files.createTempDirectory("srcRootCtagsValidationTest");
5762
env.setSourceRoot(tmpSourceRoot.toString());
5863
assertTrue(env.getSourceRootFile().exists());
5964

60-
assertTrue(CtagsUtil.validate(env.getCtags()));
65+
assertTrue(CtagsUtil.isValid(env.getCtags()));
6166

6267
Files.delete(tmpSourceRoot);
6368
}
6469

70+
/**
71+
* Simulate non-writable source root and verify that {@link CtagsUtil#isValid(String)} still returns true
72+
* as it should fall back to default temporary directory.
73+
*/
6574
@Test
66-
void testValidateWithInvalidExtraOptions() throws IOException {
75+
void testIsValidNoWritableSourceRoot() throws IOException {
76+
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
77+
Path tmpSourceRoot = Files.createTempDirectory("negativeCtagsValidationTest");
78+
env.setSourceRoot(tmpSourceRoot.toString());
79+
assertTrue(env.getSourceRootFile().exists());
80+
81+
try (MockedStatic<CtagsUtil> mocked = mockStatic(CtagsUtil.class, Mockito.CALLS_REAL_METHODS)) {
82+
mocked.when(() -> CtagsUtil.canProcessFiles(env.getSourceRootFile())).thenReturn(false);
83+
assertTrue(CtagsUtil.isValid(env.getCtags()));
84+
mocked.verify(() -> CtagsUtil.canProcessFiles(eq(env.getSourceRootFile())),
85+
times(2)); // one extra for the lambda call above
86+
}
87+
88+
Files.delete(tmpSourceRoot);
89+
}
90+
91+
@Test
92+
void testIsValidWithInvalidExtraOptions() throws IOException {
6793
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
6894
Path tmpSourceRoot = Files.createTempDirectory("srcRootCtagsValidationTestExtraArgs");
6995
env.setSourceRoot(tmpSourceRoot.toString());
@@ -74,7 +100,7 @@ void testValidateWithInvalidExtraOptions() throws IOException {
74100
String extraOptionsAbsPath = extraOptionsPath.toAbsolutePath().toString();
75101

76102
env.setCTagsExtraOptionsFile(extraOptionsAbsPath);
77-
assertFalse(CtagsUtil.validate(env.getCtags()));
103+
assertFalse(CtagsUtil.isValid(env.getCtags()));
78104

79105
// cleanup
80106
env.setCTagsExtraOptionsFile(null);

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Portions Copyright (c) 2018, 2020, Chris Fraire <cfraire@me.com>.
7474
<maven-surefire.version>3.0.0-M5</maven-surefire.version>
7575
<apache-commons-lang3.version>3.13.0</apache-commons-lang3.version>
7676
<micrometer.version>1.11.4</micrometer.version>
77-
<mockito.version>3.12.4</mockito.version>
77+
<mockito.version>5.2.0</mockito.version>
7878
<commons-io.version>2.14.0</commons-io.version>
7979
</properties>
8080

0 commit comments

Comments
 (0)