diff --git a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/ShellTest.java b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/ShellTest.java index 6060c4d9147..1dc2a5efaac 100644 --- a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/ShellTest.java +++ b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/ShellTest.java @@ -98,17 +98,23 @@ private static void executeShell(String input, File outputHistory) throws Interr assertTrue(outputHistory.exists()); - // Validate file permissions are 600 (owner read/write only) - Set permissions = Files.getPosixFilePermissions(outputHistory.toPath()); - assertTrue(permissions.contains(PosixFilePermission.OWNER_READ), "File should be readable by owner"); - assertTrue(permissions.contains(PosixFilePermission.OWNER_WRITE), "File should be writable by owner"); - // Explicitly verify group and others cannot read - assertFalse(permissions.contains(PosixFilePermission.GROUP_READ), "File should not be readable by group"); - assertFalse(permissions.contains(PosixFilePermission.GROUP_WRITE), "File should not be writable by group"); - assertFalse(permissions.contains(PosixFilePermission.GROUP_EXECUTE), "File should not be executable by group"); - assertFalse(permissions.contains(PosixFilePermission.OTHERS_READ), "File should not be readable by others"); - assertFalse(permissions.contains(PosixFilePermission.OTHERS_WRITE), "File should not be writable by others"); - assertFalse(permissions.contains(PosixFilePermission.OTHERS_EXECUTE), "File should not be executable by others"); + // Validate file permissions are 600 on unix-type systems (owner read/write only) + if (Files.getFileStore(outputHistory.toPath()).supportsFileAttributeView("posix")) { + Set permissions = Files.getPosixFilePermissions(outputHistory.toPath()); + assertTrue(permissions.contains(PosixFilePermission.OWNER_READ), "File should be readable by owner"); + assertTrue(permissions.contains(PosixFilePermission.OWNER_WRITE), "File should be writable by owner"); + // Explicitly verify group and others cannot read + assertFalse(permissions.contains(PosixFilePermission.GROUP_READ), "File should not be readable by group"); + assertFalse(permissions.contains(PosixFilePermission.GROUP_WRITE), "File should not be writable by group"); + assertFalse(permissions.contains(PosixFilePermission.GROUP_EXECUTE), "File should not be executable by group"); + assertFalse(permissions.contains(PosixFilePermission.OTHERS_READ), "File should not be readable by others"); + assertFalse(permissions.contains(PosixFilePermission.OTHERS_WRITE), "File should not be writable by others"); + assertFalse(permissions.contains(PosixFilePermission.OTHERS_EXECUTE), "File should not be executable by others"); + } else { + // Fallback for Windows: Verify owner can read/write + assertTrue(outputHistory.canRead(), "File should be readable"); + assertTrue(outputHistory.canWrite(), "File should be writable"); + } } finally { System.clearProperty("artemis.instance"); diff --git a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/messages/ProducerThreadTest.java b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/messages/ProducerThreadTest.java index 813dbf46446..2d2d1b83340 100644 --- a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/messages/ProducerThreadTest.java +++ b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/messages/ProducerThreadTest.java @@ -225,7 +225,7 @@ public void testBadMessagePropertyType() throws Exception { producer.setProperties(createJsonProperty("myType", "myKey", "myValue")); producer.applyProperties(mockMessage); - assertEquals("Unable to set property: myKey. Did not recognize type: myType. Supported types are: boolean, int, long, byte, short, float, double, string.\n", context.getStderr()); + assertEquals("Unable to set property: myKey. Did not recognize type: myType. Supported types are: boolean, int, long, byte, short, float, double, string." + System.lineSeparator(), context.getStderr()); } private static String createJsonProperty(String type, String key, String value) { diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/MessageSerializerTest.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/MessageSerializerTest.java index a13e7fb9798..994a3f51d43 100644 --- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/MessageSerializerTest.java +++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/MessageSerializerTest.java @@ -152,24 +152,34 @@ private void exportMessages(String address, File output) throws Exception { } private void exportMessages(String address, int messageCount, boolean durable, String clientId, File output) throws Exception { - new Consumer() - .setFile(output.getAbsolutePath()) - .setDurable(durable) - .setDestination(address) - .setMessageCount(messageCount) - .setClientID(clientId) - .setUser("admin") - .setPassword("admin") - .execute(new TestActionContext()); + try { + new Consumer() + .setFile(output.getAbsolutePath()) + .setDurable(durable) + .setDestination(address) + .setMessageCount(messageCount) + .setClientID(clientId) + .setUser("admin") + .setPassword("admin") + .execute(new TestActionContext()); + } finally { + // release file handles + System.gc(); + } } private void importMessages(String address, File input) throws Exception { - new Producer() - .setFile(input.getAbsolutePath()) - .setDestination(address) - .setUser("admin") - .setPassword("admin") - .execute(new TestActionContext()); + try { + new Producer() + .setFile(input.getAbsolutePath()) + .setDestination(address) + .setUser("admin") + .setPassword("admin") + .execute(new TestActionContext()); + } finally { + // release file handles + System.gc(); + } } private void createBothTypeAddress(String address) throws Exception { diff --git a/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/NetworkHealthTest.java b/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/NetworkHealthTest.java index f3508008ef2..0d84690864e 100644 --- a/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/NetworkHealthTest.java +++ b/artemis-commons/src/test/java/org/apache/activemq/artemis/utils/NetworkHealthTest.java @@ -327,12 +327,18 @@ public boolean purePing(InetAddress address) throws IOException, InterruptedExce @Test @Timeout(30) public void testPurePingTimeout() throws Exception { - NetworkHealthCheck check = new NetworkHealthCheck(null, 100, 2000); + int timeout = 2000; + + // Add a "tolerance" for Windows, since it reports less time spent in timeout than the networkTimeout parameter (around 200ms) + int tolerance = 500; + + NetworkHealthCheck check = new NetworkHealthCheck(null, 100, timeout); long time = System.currentTimeMillis(); //[RFC1166] reserves the address block 192.0.2.0/24 for test. assertFalse(check.purePing(InetAddress.getByName("192.0.2.0"))); - assertTrue(System.currentTimeMillis() - time >= 2000); + + assertTrue(System.currentTimeMillis() - time >= (timeout - tolerance)); } } diff --git a/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/XmlUtilTest.java b/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/XmlUtilTest.java index c2dac261303..aa5d800493c 100644 --- a/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/XmlUtilTest.java +++ b/artemis-dto/src/test/java/org/apache/activemq/artemis/dto/XmlUtilTest.java @@ -30,13 +30,18 @@ public class XmlUtilTest extends ArtemisTestCase { @Test - public void testPropertySubstituion(@TempDir Path tempDir) throws Exception { + public void testPropertySubstitution(@TempDir Path tempDir) throws Exception { final String SYSTEM_PROP_NAME = getTestMethodName() + "SysPropName"; final String SYSTEM_PROP_VALUE = getTestMethodName() + "SysPropValue"; System.setProperty(SYSTEM_PROP_NAME, SYSTEM_PROP_VALUE); // since System.getenv() returns an immutable Map we rely here on an environment variable that is likely to exist - final String ENV_VAR_NAME = "HOME"; + String ENV_VAR_NAME = "HOME"; + + // override to USERPROFILE if OS is windows + if (System.getProperty("os.name").toLowerCase().contains("win")) { + ENV_VAR_NAME = "USERPROFILE"; + } BrokerDTO brokerDTO = getBrokerDTO(tempDir, SYSTEM_PROP_NAME, ENV_VAR_NAME); assertEquals(SYSTEM_PROP_VALUE, ((JaasSecurityDTO)brokerDTO.security).domain); @@ -44,7 +49,7 @@ public void testPropertySubstituion(@TempDir Path tempDir) throws Exception { } @Test - public void testPropertySubstituionPrecedence(@TempDir Path tempDir) throws Exception { + public void testPropertySubstitutionPrecedence(@TempDir Path tempDir) throws Exception { final String SYSTEM_PROP_NAME = "HOME"; final String SYSTEM_PROP_VALUE = getTestMethodName() + "SysPropValue"; System.setProperty(SYSTEM_PROP_NAME, SYSTEM_PROP_VALUE); diff --git a/artemis-lockmanager/artemis-lockmanager-ri/src/main/java/org/apache/activemq/artemis/lockmanager/file/FileBasedLockManager.java b/artemis-lockmanager/artemis-lockmanager-ri/src/main/java/org/apache/activemq/artemis/lockmanager/file/FileBasedLockManager.java index 3329b88bf79..61f103c9a91 100644 --- a/artemis-lockmanager/artemis-lockmanager-ri/src/main/java/org/apache/activemq/artemis/lockmanager/file/FileBasedLockManager.java +++ b/artemis-lockmanager/artemis-lockmanager-ri/src/main/java/org/apache/activemq/artemis/lockmanager/file/FileBasedLockManager.java @@ -137,7 +137,7 @@ public DistributedLock getDistributedLock(String lockId) throws ExecutionExcepti @Override public MutableLong getMutableLong(final String mutableLongId) throws ExecutionException { // use a lock file - but with a prefix - final FileDistributedLock fileDistributedLock = (FileDistributedLock) getDistributedLock("ML:" + mutableLongId); + final FileDistributedLock fileDistributedLock = (FileDistributedLock) getDistributedLock("ML_" + mutableLongId); return new MutableLong() { @Override public String getMutableLongId() { diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java index ad129038f2f..d7eeeea7f37 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImplTest.java @@ -2447,7 +2447,7 @@ public void testTextPropertiesReaderFromFile() throws Exception { try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile); PrintWriter printWriter = new PrintWriter(fileOutputStream)) { for (String textProperty : textProperties) { - printWriter.println(textProperty); + printWriter.print(textProperty + "\n"); } } @@ -2971,12 +2971,15 @@ public void testRegxPropertiesFilesInDir() throws Exception { File tmpFile = File.createTempFile("a_stuff", ".properties", temporaryFolder); Properties properties = new Properties(); properties.put("name", "a"); - properties.store(new FileOutputStream(tmpFile), null); - + try (FileOutputStream out = new FileOutputStream(tmpFile)) { + properties.store(out, null); + } tmpFile = File.createTempFile("b_stuff", ".0-properties", temporaryFolder); properties = new Properties(); properties.put("name", "0"); - properties.store(new FileOutputStream(tmpFile), null); + try (FileOutputStream out = new FileOutputStream(tmpFile)) { + properties.store(out, null); + } ConfigurationImpl configuration = new ConfigurationImpl(); configuration.parseProperties(temporaryFolder + "/"); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManagerTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManagerTest.java index 29788e727f5..183b36c7420 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManagerTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/impl/FileLockNodeManagerTest.java @@ -43,14 +43,17 @@ public class FileLockNodeManagerTest { @Timeout(3) public void testChannelClosed() throws Exception { FileLockNodeManager manager = new FileLockNodeManager(temporaryFolder, false); + try { + // calling this method sets up the internal FileChannel as it would be in normal usage + manager.pausePrimaryServer(); - // calling this method sets up the internal FileChannel as it would be in normal usage - manager.pausePrimaryServer(); - - // now close the channel so we can ensure it throws - manager.getChannel().close(); + // now close the channel so we can ensure it throws + manager.getChannel().close(); - assertThrows(ClosedChannelException.class, () -> manager.lock(0)); + assertThrows(ClosedChannelException.class, () -> manager.lock(0)); + } finally { + manager.stop(); + } } @Test diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModuleTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModuleTest.java index 8bc29fb3fa8..9e187650036 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModuleTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/LDAPLoginModuleTest.java @@ -33,6 +33,8 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.net.URL; +import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -99,9 +101,10 @@ public void setUp() throws Exception { directoryService.setAllowAnonymousAccess(true); ldapServer.setDirectoryService(directoryService); - String keystore = Objects.requireNonNull(this.getClass().getClassLoader(). - getResource("server-keystore-without-ca.p12")).getFile(); - ldapServer.setKeystoreFile(keystore); + URL keystore = Objects.requireNonNull(this.getClass().getClassLoader(). + getResource("server-keystore-without-ca.p12")); + String keystorePath = Paths.get(keystore.toURI()).toString(); + ldapServer.setKeystoreFile(keystorePath); ldapServer.setCertificatePassword("securepass"); ldapServer.start(); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/PropertiesLoaderTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/PropertiesLoaderTest.java index aa36e13e8f7..33fa93186f4 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/PropertiesLoaderTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/PropertiesLoaderTest.java @@ -40,8 +40,9 @@ void load(@TempDir Path tempDir) throws IOException { properties.put("p2", "b"); properties.put("p3", "/b/"); // regexp - FileWriter fileWriter = new FileWriter(file.toFile()); - properties.store(fileWriter, ""); + try (FileWriter fileWriter = new FileWriter(file.toFile())) { + properties.store(fileWriter, ""); + } PropertiesLoader underTest = new PropertiesLoader(); Map options = new HashMap(); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/kubernetes/client/KubernetesClientImplTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/kubernetes/client/KubernetesClientImplTest.java index d0600010250..638f2cc167b 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/kubernetes/client/KubernetesClientImplTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/jaas/kubernetes/client/KubernetesClientImplTest.java @@ -33,6 +33,7 @@ import java.io.File; import java.lang.invoke.MethodHandles; import java.net.URL; +import java.nio.file.Paths; import java.util.Map; import java.util.Set; @@ -72,7 +73,7 @@ public class KubernetesClientImplTest { "kind": "TokenReview", "spec": {"token": "kermit_token"}}"""; @BeforeAll - public static void startServer() { + public static void startServer() throws Exception { ConfigurationProperties.directoryToSaveDynamicSSLCertificate(tempDir.getAbsolutePath()); ConfigurationProperties.certificateAuthorityPrivateKey(KubernetesClientImplTest.class.getClassLoader().getResource("server-ca.pem").getPath()); ConfigurationProperties.certificateAuthorityCertificate(KubernetesClientImplTest.class.getClassLoader().getResource("server-ca-cert.pem").getPath()); @@ -86,10 +87,13 @@ public static void startServer() { assertNotNull(mockServer); assertTrue(mockServer.hasStarted()); + + URL token = KubernetesClientImplTest.class.getClassLoader().getResource("client_token"); + String tokenPath = Paths.get(token.toURI()).toString(); + System.setProperty("KUBERNETES_SERVICE_HOST", host); System.setProperty("KUBERNETES_SERVICE_PORT", port); - System.setProperty("KUBERNETES_TOKEN_PATH", - KubernetesClientImplTest.class.getClassLoader().getResource("client_token").getPath()); + System.setProperty("KUBERNETES_TOKEN_PATH", tokenPath); URL caPath = KubernetesClientImplTest.class.getClassLoader() .getResource("client-and-server-ca-certs.pem"); diff --git a/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java b/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java index 89f37e52109..5cf42b5d867 100644 --- a/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java +++ b/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java @@ -33,7 +33,9 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.http.HttpClient; +import java.nio.file.FileSystemException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; @@ -103,6 +105,7 @@ import org.eclipse.jetty.ee9.webapp.WebInfConfiguration; import org.eclipse.jetty.util.thread.ThreadPool; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -124,9 +127,18 @@ public class WebServerComponentTest extends ArtemisTestCase { static final String URL = System.getProperty("url", "http://localhost:8161/WebServerComponentTest.txt"); static final String SECURE_URL = System.getProperty("url", "https://localhost:8448/WebServerComponentTest.txt"); - static final String KEY_STORE_PATH = WebServerComponentTest.class.getClassLoader().getResource("server-keystore.p12").getFile(); + private static String getResourcePath(String resourceName) { + try { + URI uri = WebServerComponentTest.class.getClassLoader().getResource(resourceName).toURI(); + return Path.of(uri).toString(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + static final String KEY_STORE_PATH = getResourcePath("server-keystore.p12"); - static final String PEM_KEY_STORE_PATH = WebServerComponentTest.class.getClassLoader().getResource("server-keystore.pemcfg").getFile(); + static final String PEM_KEY_STORE_PATH = getResourcePath("server-keystore.pemcfg"); static final String KEY_STORE_PASSWORD = "securepass"; @@ -559,8 +571,16 @@ public void testSSLAutoReload(boolean useSymbolicLinks) throws Exception { String keyStorePath; if (useSymbolicLinks) { - keyStorePath = Files.createSymbolicLink(storeFolder.toPath().resolve( - "store-keystore.p12"), keyStoreFile.toPath()).toString(); + try { + keyStorePath = Files.createSymbolicLink(storeFolder.toPath().resolve( + "store-keystore.p12"), keyStoreFile.toPath()).toString(); + } catch (FileSystemException e) { + // Check if privileges are missing on Windows + if (e.getMessage() != null && e.getMessage().contains("A required privilege is not held by the client")) { + Assumptions.assumeTrue(false, "Skipping test: Windows account lacks the privilege to create symbolic links."); + } + throw e; + } } else { keyStorePath = keyStoreFile.getAbsolutePath(); } @@ -633,24 +653,40 @@ private void testSSLAutoReloadPemConfigSources(boolean useSymbolicLinks) throws String sourceKey; String sourceCert; if (useSymbolicLinks) { - sourceKey = Files.createSymbolicLink(storeFolder.toPath().resolve( - "store-key.pem"), serverKeyFile.toPath()).toString(); - sourceCert = Files.createSymbolicLink(storeFolder.toPath().resolve( - "store-cert.pem"), serverCertFile.toPath()).toString(); + try { + sourceKey = Files.createSymbolicLink(storeFolder.toPath().resolve( + "store-key.pem"), serverKeyFile.toPath()).toString(); + sourceCert = Files.createSymbolicLink(storeFolder.toPath().resolve( + "store-cert.pem"), serverCertFile.toPath()).toString(); + } catch (FileSystemException e) { + // Check if privileges are missing on Windows + if (e.getMessage() != null && e.getMessage().contains("A required privilege is not held by the client")) { + Assumptions.assumeTrue(false, "Skipping test: Windows account lacks the privilege to create symbolic links."); + } + throw e; + } } else { sourceKey = serverKeyFile.getAbsolutePath(); sourceCert = serverCertFile.getAbsolutePath(); } Files.write(serverPemConfigFile.toPath(), Arrays.asList(new String[]{ - "source.key=" + sourceKey, - "source.cert=" + sourceCert + "source.key=" + sourceKey.replace("\\", "/"), + "source.cert=" + sourceCert.replace("\\", "/") })); String keyStorePath; if (useSymbolicLinks) { - keyStorePath = Files.createSymbolicLink(storeFolder.toPath().resolve( - "store-pem-config.properties"), serverPemConfigFile.toPath()).toString(); + try { + keyStorePath = Files.createSymbolicLink(storeFolder.toPath().resolve( + "store-pem-config.properties"), serverPemConfigFile.toPath()).toString(); + } catch (FileSystemException e) { + // Check if privileges are missing on Windows + if (e.getMessage() != null && e.getMessage().contains("A required privilege is not held by the client")) { + Assumptions.assumeTrue(false, "Skipping test: Windows account lacks the privilege to create symbolic links."); + } + throw e; + } } else { keyStorePath = serverPemConfigFile.getAbsolutePath(); } @@ -746,10 +782,11 @@ public HttpRoute determineRoute(HttpHost host, public void simpleSecureServerWithClientAuth() throws Exception { BindingDTO bindingDTO = new BindingDTO(); bindingDTO.uri = "https://localhost:0"; - bindingDTO.setKeyStorePath(KEY_STORE_PATH); + String keyStorePath = KEY_STORE_PATH.replace("\\", "/"); + bindingDTO.setKeyStorePath(keyStorePath); bindingDTO.setKeyStorePassword(KEY_STORE_PASSWORD); bindingDTO.setClientAuth(true); - bindingDTO.setTrustStorePath(KEY_STORE_PATH); + bindingDTO.setTrustStorePath(keyStorePath); bindingDTO.setTrustStorePassword(KEY_STORE_PASSWORD); WebServerDTO webServerDTO = new WebServerDTO(); webServerDTO.setBindings(Collections.singletonList(bindingDTO)); diff --git a/pom.xml b/pom.xml index 31255ef7d48..ea21e333b19 100644 --- a/pom.xml +++ b/pom.xml @@ -267,7 +267,7 @@ -Djava.net.preferIPv4Stack=true -Djdk.attach.allowAttachSelf=true -Dartemis.distribution.output="${artemis.distribution.output}" - -Dlog4j2.configurationFile="file:${activemq.basedir}/tests/config/${logging.config}" + -Dlog4j2.configurationFile="${activemq.basedir}/tests/config/${logging.config}" ${project.basedir} false