From 36f89635027bed22acf53c43d47b06502d3c7286 Mon Sep 17 00:00:00 2001 From: Vijay N Date: Tue, 27 May 2025 16:32:02 +0530 Subject: [PATCH 1/6] - Added getPropertiesBySource() contract to OSGIConfigProperties interface - Added implementation in DefaultKillbillConfigSource and OSGIConfigPropertiesService to expose runtime resolved properties grouped by config source. - Added unit test to validate grouped property retrieval. --- .../config/DefaultKillbillConfigSource.java | 26 +++++++++++++++++++ .../TestDefaultKillbillConfigSource.java | 21 ++++++++++++++- .../osgi/api/OSGIConfigProperties.java | 16 +++++++++++- .../killbill/OSGIConfigPropertiesService.java | 11 ++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java index c62dc2f1..3f7ce028 100644 --- a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java +++ b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java @@ -23,6 +23,7 @@ import java.net.URISyntaxException; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -134,6 +135,31 @@ public Properties getProperties() { return result; } + @Override + public Map> getPropertiesBySource() { + final Map> result = new HashMap<>(); + final Map systemProps = new HashMap<>(); + + properties.stringPropertyNames().forEach(key -> systemProps.put(key, properties.getProperty(key))); + result.put("SystemProperties", systemProps); + + final Map> runtimeBySource = RuntimeConfigRegistry.getAllBySource(); + runtimeBySource.forEach((source, props) -> { + final Map filteredProps = new HashMap<>(); + props.forEach((key, value) -> { + if (!systemProps.containsKey(key)) { + filteredProps.put(key, value); + } + }); + + if (!filteredProps.isEmpty()) { + result.put(source, filteredProps); + } + }); + + return result; + } + private Properties loadPropertiesFromFileOrSystemProperties() { // Chicken-egg problem. It would be nice to have the property in e.g. KillbillServerConfig, // but we need to build the ConfigSource first... diff --git a/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java b/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java index 05f44d51..8c494fa0 100644 --- a/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java +++ b/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java @@ -27,9 +27,9 @@ import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.exceptions.EncryptionOperationNotPossibleException; import org.killbill.billing.osgi.api.OSGIConfigProperties; +import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import org.testng.Assert; import static org.killbill.billing.platform.config.DefaultKillbillConfigSource.ENVIRONMENT_VARIABLE_PREFIX; @@ -68,6 +68,25 @@ public void testGetProperties() throws URISyntaxException, IOException { Assert.assertEquals(configSource.getProperties().getProperty("1"), "A"); } + @Test(groups = "fast") + public void testGetPropertiesBySource() throws URISyntaxException, IOException { + final Map configuration = new HashMap<>(); + configuration.put("org.killbill.dao.user", "root"); + configuration.put("org.killbill.dao.password", "password"); + + final OSGIConfigProperties configSource = new DefaultKillbillConfigSource(null, configuration); + + final Map> propsBySource = configSource.getPropertiesBySource(); + + Assert.assertNotNull(propsBySource); + Assert.assertFalse(propsBySource.isEmpty()); + + final Map defaultProps = propsBySource.get("SystemProperties"); + Assert.assertNotNull(defaultProps); + Assert.assertEquals(defaultProps.get("org.killbill.dao.user"), "root"); + Assert.assertEquals(defaultProps.get("org.killbill.dao.password"), "password"); + } + @Test(groups = "fast") public void testFromEnvVariableName() throws IOException, URISyntaxException { final DefaultKillbillConfigSource configSource = new DefaultKillbillConfigSource(); diff --git a/osgi-api/src/main/java/org/killbill/billing/osgi/api/OSGIConfigProperties.java b/osgi-api/src/main/java/org/killbill/billing/osgi/api/OSGIConfigProperties.java index 53d99fb7..0aa4937b 100644 --- a/osgi-api/src/main/java/org/killbill/billing/osgi/api/OSGIConfigProperties.java +++ b/osgi-api/src/main/java/org/killbill/billing/osgi/api/OSGIConfigProperties.java @@ -19,6 +19,7 @@ package org.killbill.billing.osgi.api; +import java.util.Map; import java.util.Properties; /** @@ -28,13 +29,26 @@ public interface OSGIConfigProperties { /** + * Retrieves the value of the given property. + * * @param propertyName the system property name * @return the value of the property */ public String getString(final String propertyName); /** - * @return all knows system properties (for the JVM) + * Returns all runtime resolved properties as a flat {@link Properties} object. + * + * @return all known configuration properties */ public Properties getProperties(); + + /** + * Returns all runtime resolved properties grouped by their respective source. + * Each key in the outer map represents the source name (e.g., "SystemProperties", "KillbillServerConfig", "CatalogConfig"), + * and the corresponding value is a map of property names to values loaded from that source. + * + * @return a map of configuration sources to their respective key-value property sets. + */ + public Map> getPropertiesBySource(); } diff --git a/osgi-bundles/libs/killbill/src/main/java/org/killbill/billing/osgi/libs/killbill/OSGIConfigPropertiesService.java b/osgi-bundles/libs/killbill/src/main/java/org/killbill/billing/osgi/libs/killbill/OSGIConfigPropertiesService.java index eab5040b..04a5df00 100644 --- a/osgi-bundles/libs/killbill/src/main/java/org/killbill/billing/osgi/libs/killbill/OSGIConfigPropertiesService.java +++ b/osgi-bundles/libs/killbill/src/main/java/org/killbill/billing/osgi/libs/killbill/OSGIConfigPropertiesService.java @@ -19,6 +19,7 @@ package org.killbill.billing.osgi.libs.killbill; +import java.util.Map; import java.util.Properties; import org.killbill.billing.osgi.api.OSGIConfigProperties; @@ -59,4 +60,14 @@ public Properties executeWithService(final OSGIConfigProperties service) { } }); } + + @Override + public Map> getPropertiesBySource() { + return withServiceTracker(killbillTracker, new APICallback<>(OSGIConfigProperties.class.getName()) { + @Override + public Map> executeWithService(final OSGIConfigProperties service) { + return service.getPropertiesBySource(); + } + }); + } } From 6509b49dd7b3666a54e6235dafcc349c5b953e36 Mon Sep 17 00:00:00 2001 From: Vijay N Date: Wed, 4 Jun 2025 18:14:29 +0530 Subject: [PATCH 2/6] * Added loadAwsSsmProperties() to load parameters from AWS SSM. * Included "AwsSsmProperties" category in getPropertiesBySource(). * Categorized properties by source: system, env, killbill, runtime, ssm, etc. * Added helper methods to support property merging and filtering * Updated getProperties() to ensure all sources are loaded * Added required AWS SDK v2 dependencies for SSM fetch. --- base/pom.xml | 4 + .../config/DefaultKillbillConfigSource.java | 112 +++++++++++++++++- pom.xml | 25 ++++ 3 files changed, 136 insertions(+), 5 deletions(-) diff --git a/base/pom.xml b/base/pom.xml index 46a8f979..bd14bde1 100644 --- a/base/pom.xml +++ b/base/pom.xml @@ -110,5 +110,9 @@ testng test + + software.amazon.awssdk + ssm + diff --git a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java index 3f7ce028..579f2d15 100644 --- a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java +++ b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.net.URISyntaxException; +import java.nio.file.Paths; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -43,6 +44,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.ssm.SsmClient; +import software.amazon.awssdk.services.ssm.model.GetParametersByPathRequest; +import software.amazon.awssdk.services.ssm.model.GetParametersByPathResponse; +import software.amazon.awssdk.services.ssm.model.Parameter; +import software.amazon.awssdk.services.ssm.model.ParameterType; + public class DefaultKillbillConfigSource implements KillbillConfigSource, OSGIConfigProperties { private static final Object lock = new Object(); @@ -69,6 +77,12 @@ public class DefaultKillbillConfigSource implements KillbillConfigSource, OSGICo private static volatile int GMT_WARNING = NOT_SHOWN; private static volatile int ENTROPY_WARNING = NOT_SHOWN; + private final Map> runtimeConfigBySource = new HashMap<>(); + + private final String awsRegion = System.getProperty("com.killbill.aws.region"); + + private final String ssmStorePath = System.getProperty("com.killbill.aws.ssm.storePath"); + private final Properties properties; public DefaultKillbillConfigSource() throws IOException, URISyntaxException { @@ -89,6 +103,10 @@ public DefaultKillbillConfigSource(@Nullable final String file, final Map entry : extraDefaultProperties.entrySet()) { @@ -97,6 +115,8 @@ public DefaultKillbillConfigSource(@Nullable final String file, final Map> getPropertiesBySource() { - final Map> result = new HashMap<>(); final Map systemProps = new HashMap<>(); properties.stringPropertyNames().forEach(key -> systemProps.put(key, properties.getProperty(key))); - result.put("SystemProperties", systemProps); final Map> runtimeBySource = RuntimeConfigRegistry.getAllBySource(); runtimeBySource.forEach((source, props) -> { @@ -153,22 +171,35 @@ public Map> getPropertiesBySource() { }); if (!filteredProps.isEmpty()) { - result.put(source, filteredProps); + runtimeConfigBySource.put(source, filteredProps); } }); - return result; + runtimeConfigBySource.putAll(runtimeBySource); + + final Map ssmProps = loadAwsSsmProperties(); + if (!ssmProps.isEmpty()) { + runtimeConfigBySource.put("AwsSsmProperties", ssmProps); + } + + return runtimeConfigBySource; } private Properties loadPropertiesFromFileOrSystemProperties() { // Chicken-egg problem. It would be nice to have the property in e.g. KillbillServerConfig, // but we need to build the ConfigSource first... final String propertiesFileLocation = System.getProperty(PROPERTIES_FILE); + if (propertiesFileLocation != null) { try { // Ignore System Properties if we're loading from a file final Properties properties = new Properties(); properties.load(UriAccessor.accessUri(propertiesFileLocation)); + + final String category = extractFileNameFromPath(propertiesFileLocation); + + runtimeConfigBySource.put(category, propertiesToMap(properties)); + return properties; } catch (final IOException e) { logger.warn("Unable to access properties file, defaulting to system properties", e); @@ -177,7 +208,11 @@ private Properties loadPropertiesFromFileOrSystemProperties() { } } - return new Properties(System.getProperties()); + final Properties systemProperties = new Properties(System.getProperties()); + + runtimeConfigBySource.put("SystemProperties", propertiesToMap(systemProperties)); + + return systemProperties; } @VisibleForTesting @@ -235,6 +270,13 @@ protected void populateDefaultProperties() { } } } + + final Map defaultProps = propertiesToMap(defaultProperties); + final Map defaultSystemProps = propertiesToMap(defaultSystemProperties); + + defaultSystemProps.putAll(defaultProps); + + runtimeConfigBySource.put("DefaultSystemProperties", defaultSystemProps); } @VisibleForTesting @@ -270,6 +312,9 @@ protected Properties getDefaultSystemProperties() { private void overrideWithEnvironmentVariables() { // Find all Kill Bill properties in the environment variables final Map env = System.getenv(); + + final Map kbEnvVariables = new HashMap<>(); + for (final Entry entry : env.entrySet()) { if (!entry.getKey().startsWith(ENVIRONMENT_VARIABLE_PREFIX)) { continue; @@ -277,8 +322,12 @@ private void overrideWithEnvironmentVariables() { final String propertyName = fromEnvVariableName(entry.getKey()); final String value = entry.getValue(); + + kbEnvVariables.put(propertyName, value); properties.setProperty(propertyName, value); } + + runtimeConfigBySource.put("EnvironmentVariables", kbEnvVariables); } @VisibleForTesting @@ -339,4 +388,57 @@ private Optional decryptableValue(final String value) { } return Optional.empty(); } + + private Map loadAwsSsmProperties() { + final Map ssmProps = new HashMap<>(); + + if (Strings.isNullOrEmpty(awsRegion) || Strings.isNullOrEmpty(ssmStorePath)) { + return ssmProps; + } + + final SsmClient ssmClient = SsmClient.builder().region(Region.of(awsRegion)).build(); + final GetParametersByPathRequest parametersRequest = GetParametersByPathRequest.builder() + .path(ssmStorePath) + .withDecryption(true) + .build(); + final GetParametersByPathResponse parameterResponse = ssmClient.getParametersByPath(parametersRequest); + + final String prefix = ssmStorePath.endsWith("/") ? ssmStorePath : ssmStorePath + "/"; + for (final Parameter parameter : parameterResponse.parameters()) { + final String key = parameter.name().replace(prefix, ""); + final String value = parameter.value(); + + final String safeValue = parameter.type() == ParameterType.SECURE_STRING + ? "*".repeat(value.length()) + : value; + + logger.info("Assigning SSM value [{}] for [{}]", safeValue, key); + + properties.put(key, safeValue); + ssmProps.put(key, safeValue); + } + + return ssmProps; + } + + private String extractFileNameFromPath(String path) { + if (path == null || path.isEmpty()) { + return "unknown.properties"; + } + + if (path.startsWith("file://")) { + path = path.substring("file://".length()); + } + + return Paths.get(path).getFileName().toString(); + } + + private Map propertiesToMap(final Properties props) { + final Map propertiesMap = new HashMap<>(); + for (final Map.Entry entry : props.entrySet()) { + propertiesMap.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue())); + } + + return propertiesMap; + } } diff --git a/pom.xml b/pom.xml index 1a105ce3..1a3ae5f7 100644 --- a/pom.xml +++ b/pom.xml @@ -193,6 +193,31 @@ killbill-platform-test ${project.version} + + software.amazon.awssdk + bom + 2.20.45 + pom + import + + + + software.amazon.awssdk + ssm + + + + commons-logging + commons-logging + + + + commons-codec + commons-codec + + + + From e9434b1a310d44279fd30c0d1388060112353485 Mon Sep 17 00:00:00 2001 From: Vijay N Date: Thu, 5 Jun 2025 09:46:11 +0530 Subject: [PATCH 3/6] * Removed AWS dependencies and the functionality about loading properties from SSM. --- base/pom.xml | 4 -- .../config/DefaultKillbillConfigSource.java | 48 ------------------- .../TestDefaultKillbillConfigSource.java | 2 +- pom.xml | 25 ---------- 4 files changed, 1 insertion(+), 78 deletions(-) diff --git a/base/pom.xml b/base/pom.xml index bd14bde1..46a8f979 100644 --- a/base/pom.xml +++ b/base/pom.xml @@ -110,9 +110,5 @@ testng test - - software.amazon.awssdk - ssm - diff --git a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java index 579f2d15..8f0fc693 100644 --- a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java +++ b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java @@ -44,13 +44,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.ssm.SsmClient; -import software.amazon.awssdk.services.ssm.model.GetParametersByPathRequest; -import software.amazon.awssdk.services.ssm.model.GetParametersByPathResponse; -import software.amazon.awssdk.services.ssm.model.Parameter; -import software.amazon.awssdk.services.ssm.model.ParameterType; - public class DefaultKillbillConfigSource implements KillbillConfigSource, OSGIConfigProperties { private static final Object lock = new Object(); @@ -79,10 +72,6 @@ public class DefaultKillbillConfigSource implements KillbillConfigSource, OSGICo private final Map> runtimeConfigBySource = new HashMap<>(); - private final String awsRegion = System.getProperty("com.killbill.aws.region"); - - private final String ssmStorePath = System.getProperty("com.killbill.aws.ssm.storePath"); - private final Properties properties; public DefaultKillbillConfigSource() throws IOException, URISyntaxException { @@ -177,11 +166,6 @@ public Map> getPropertiesBySource() { runtimeConfigBySource.putAll(runtimeBySource); - final Map ssmProps = loadAwsSsmProperties(); - if (!ssmProps.isEmpty()) { - runtimeConfigBySource.put("AwsSsmProperties", ssmProps); - } - return runtimeConfigBySource; } @@ -389,38 +373,6 @@ private Optional decryptableValue(final String value) { return Optional.empty(); } - private Map loadAwsSsmProperties() { - final Map ssmProps = new HashMap<>(); - - if (Strings.isNullOrEmpty(awsRegion) || Strings.isNullOrEmpty(ssmStorePath)) { - return ssmProps; - } - - final SsmClient ssmClient = SsmClient.builder().region(Region.of(awsRegion)).build(); - final GetParametersByPathRequest parametersRequest = GetParametersByPathRequest.builder() - .path(ssmStorePath) - .withDecryption(true) - .build(); - final GetParametersByPathResponse parameterResponse = ssmClient.getParametersByPath(parametersRequest); - - final String prefix = ssmStorePath.endsWith("/") ? ssmStorePath : ssmStorePath + "/"; - for (final Parameter parameter : parameterResponse.parameters()) { - final String key = parameter.name().replace(prefix, ""); - final String value = parameter.value(); - - final String safeValue = parameter.type() == ParameterType.SECURE_STRING - ? "*".repeat(value.length()) - : value; - - logger.info("Assigning SSM value [{}] for [{}]", safeValue, key); - - properties.put(key, safeValue); - ssmProps.put(key, safeValue); - } - - return ssmProps; - } - private String extractFileNameFromPath(String path) { if (path == null || path.isEmpty()) { return "unknown.properties"; diff --git a/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java b/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java index 8c494fa0..8e6191a0 100644 --- a/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java +++ b/base/src/test/java/org/killbill/billing/platform/config/TestDefaultKillbillConfigSource.java @@ -81,7 +81,7 @@ public void testGetPropertiesBySource() throws URISyntaxException, IOException { Assert.assertNotNull(propsBySource); Assert.assertFalse(propsBySource.isEmpty()); - final Map defaultProps = propsBySource.get("SystemProperties"); + final Map defaultProps = propsBySource.get("ExtraDefaultProperties"); Assert.assertNotNull(defaultProps); Assert.assertEquals(defaultProps.get("org.killbill.dao.user"), "root"); Assert.assertEquals(defaultProps.get("org.killbill.dao.password"), "password"); diff --git a/pom.xml b/pom.xml index 1a3ae5f7..1a105ce3 100644 --- a/pom.xml +++ b/pom.xml @@ -193,31 +193,6 @@ killbill-platform-test ${project.version} - - software.amazon.awssdk - bom - 2.20.45 - pom - import - - - - software.amazon.awssdk - ssm - - - - commons-logging - commons-logging - - - - commons-codec - commons-codec - - - - From 4e7035137eb81734cf0ad9deb5882db651a7f752 Mon Sep 17 00:00:00 2001 From: Vijay N Date: Mon, 9 Jun 2025 15:01:17 +0530 Subject: [PATCH 4/6] * Fixed system properties loading: used System.getProperties() directly to access -D flags. --- .../billing/platform/config/DefaultKillbillConfigSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java index 8f0fc693..622b9c94 100644 --- a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java +++ b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java @@ -192,7 +192,7 @@ private Properties loadPropertiesFromFileOrSystemProperties() { } } - final Properties systemProperties = new Properties(System.getProperties()); + final Properties systemProperties = System.getProperties(); runtimeConfigBySource.put("SystemProperties", propertiesToMap(systemProperties)); From 897ba322bb1c92b9fe01b400da0c82c4dea35df1 Mon Sep 17 00:00:00 2001 From: Vijay N Date: Mon, 23 Jun 2025 12:26:11 +0530 Subject: [PATCH 5/6] * Upgraded killbill-oss-parent to the latest * Fixed bugs identified by SpotBugs Maven plugin. --- .../platform/config/DefaultKillbillConfigSource.java | 11 +++++++++-- pom.xml | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java index 622b9c94..75ad1645 100644 --- a/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java +++ b/base/src/main/java/org/killbill/billing/platform/config/DefaultKillbillConfigSource.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.net.URISyntaxException; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.Enumeration; @@ -166,7 +167,8 @@ public Map> getPropertiesBySource() { runtimeConfigBySource.putAll(runtimeBySource); - return runtimeConfigBySource; + // Returning a shallow copy to satisfy SpotBugs (EI_EXPOSE_REP). + return new HashMap<>(runtimeConfigBySource); } private Properties loadPropertiesFromFileOrSystemProperties() { @@ -382,7 +384,12 @@ private String extractFileNameFromPath(String path) { path = path.substring("file://".length()); } - return Paths.get(path).getFileName().toString(); + final Path fileName = Paths.get(path).getFileName(); + if (fileName == null) { + return "unknown.properties"; + } + + return fileName.toString(); } private Map propertiesToMap(final Properties props) { diff --git a/pom.xml b/pom.xml index 1a105ce3..28f06429 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ org.kill-bill.billing killbill-oss-parent - 0.146.51 + 0.146.56 killbill-platform 0.41.16-SNAPSHOT From 38f01e9d21f460486e79a004ae3e9b524b4fa337 Mon Sep 17 00:00:00 2001 From: Vijay N Date: Mon, 23 Jun 2025 16:19:04 +0530 Subject: [PATCH 6/6] * Updated SetupBundleWithAssertion, handled file deletion gracefully if file is already deleted. --- .../integration/osgi/util/SetupBundleWithAssertion.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform-test/src/test/java/org/killbill/billing/beatrix/integration/osgi/util/SetupBundleWithAssertion.java b/platform-test/src/test/java/org/killbill/billing/beatrix/integration/osgi/util/SetupBundleWithAssertion.java index d87a6887..7e5d41e1 100644 --- a/platform-test/src/test/java/org/killbill/billing/beatrix/integration/osgi/util/SetupBundleWithAssertion.java +++ b/platform-test/src/test/java/org/killbill/billing/beatrix/integration/osgi/util/SetupBundleWithAssertion.java @@ -141,7 +141,9 @@ private static void deleteDirectory(final File path, final boolean deleteParent) if (f.isDirectory()) { deleteDirectory(f, true); } - Assert.assertTrue(f.delete(), "Unable to delete file " + f.getAbsolutePath()); + + final boolean deleted = f.delete(); + Assert.assertTrue(deleted || !f.exists(), "Unable to delete file " + f.getAbsolutePath()); } } if (deleteParent) { @@ -177,6 +179,7 @@ private PluginJavaConfig extractJavaBundleTestResource() { return createPluginJavaConfig(resourceUrl.getPath()); } } + return null; }