From e0463c1dcfae3377dac5f0bc3f8af19a36e4a892 Mon Sep 17 00:00:00 2001 From: yuluo-yx Date: Tue, 16 Jul 2024 16:33:46 +0800 Subject: [PATCH 1/5] [Improve] add springContextHolder unit test Signed-off-by: yuluo-yx --- .../support/SpringContextHolderTest.java | 75 +++++++++++++++++-- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/common/src/test/java/org/apache/hertzbeat/common/support/SpringContextHolderTest.java b/common/src/test/java/org/apache/hertzbeat/common/support/SpringContextHolderTest.java index c4959745501..e3b208b9694 100644 --- a/common/src/test/java/org/apache/hertzbeat/common/support/SpringContextHolderTest.java +++ b/common/src/test/java/org/apache/hertzbeat/common/support/SpringContextHolderTest.java @@ -20,28 +20,91 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + /** * Test case for {@link SpringContextHolder} */ class SpringContextHolderTest { + private ApplicationContext applicationContext; + + private ConfigurableApplicationContext configurableApplicationContext; + + private SpringContextHolder springContextHolder; + @BeforeEach - void setUp() { + public void setUp() { + + applicationContext = mock(ApplicationContext.class); + configurableApplicationContext = mock(ConfigurableApplicationContext.class); + springContextHolder = new SpringContextHolder(); } @Test - void setApplicationContext() { + public void testSetApplicationContext() throws BeansException { + + springContextHolder.setApplicationContext(configurableApplicationContext); + + assertNotNull(SpringContextHolder.getApplicationContext()); } @Test - void getApplicationContext() { + public void testGetApplicationContext() { + + springContextHolder.setApplicationContext(applicationContext); + assertNotNull(SpringContextHolder.getApplicationContext()); } @Test - void getBean() { + public void testGetBeanByClass() { + + Class beanClass = String.class; + String bean = "bean"; + when(applicationContext.getBean(beanClass)).thenReturn(bean); + + springContextHolder.setApplicationContext(applicationContext); + String retrievedBean = SpringContextHolder.getBean(beanClass); + + assertEquals(bean, retrievedBean); } @Test - void testGetBean() { + public void testShutdown() { + + springContextHolder.setApplicationContext(configurableApplicationContext); + SpringContextHolder.shutdown(); + + verify(configurableApplicationContext, times(1)).close(); + } + + @Test + public void testIsActive() { + + when(configurableApplicationContext.isActive()).thenReturn(true); + springContextHolder.setApplicationContext(configurableApplicationContext); + assertTrue(SpringContextHolder.isActive()); } -} \ No newline at end of file + + @Test + public void testAssertApplicationContextThrowsException() { + + RuntimeException exception = assertThrows(RuntimeException.class, SpringContextHolder::getApplicationContext); + assertEquals( + "applicationContext is null, please inject the springContextHolder", + exception.getMessage() + ); + } + +} From 279146ee0b5e70013a62d2598f8cf8d50c192663 Mon Sep 17 00:00:00 2001 From: yuluo-yx Date: Wed, 17 Jul 2024 15:06:54 +0800 Subject: [PATCH 2/5] [Improve] optimize ResourceBundle code & add unit test Signed-off-by: yuluo-yx --- .../support/ResourceBundleUtf8Control.java | 80 +++++++++---------- .../ResourceBundleUtf8ControlTest.java | 53 +++++++++++- common/src/test/resources/msg.properties | 1 + common/src/test/resources/msg_en.properties | 1 + 4 files changed, 89 insertions(+), 46 deletions(-) create mode 100644 common/src/test/resources/msg.properties create mode 100644 common/src/test/resources/msg_en.properties diff --git a/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java b/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java index 13448e2868a..263327e40f9 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java +++ b/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java @@ -20,21 +20,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLConnection; import java.nio.charset.StandardCharsets; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.util.Locale; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; -import lombok.extern.slf4j.Slf4j; /** * i18n resource bundle control */ -@Slf4j + public class ResourceBundleUtf8Control extends ResourceBundle.Control { private static final String JAVA_CLASS = "java.class"; @@ -55,49 +52,26 @@ public ResourceBundle newBundle(String baseName, Locale locale, String format, C // If the class isn't a ResourceBundle subclass, throw a // ClassCastException. if (ResourceBundle.class.isAssignableFrom(bundleClass)) { - bundle = bundleClass.newInstance(); + bundle = bundleClass.getDeclaredConstructor().newInstance(); } else { throw new ClassCastException(bundleClass.getName() + " cannot be cast to ResourceBundle"); } } catch (ClassNotFoundException ignored) {} - } else if (JAVA_PROPERTIES.equals(format)) { - final String resourceName = toResourceName0(bundleName, "properties"); + catch (InvocationTargetException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + } else if (JAVA_PROPERTIES.equals(format)) { + final String resourceName = toResourceName0(bundleName); if (resourceName == null) { return null; } - final ClassLoader classLoader = loader; - final boolean reloadFlag = reload; - InputStream stream; - try { - stream = AccessController.doPrivileged( - (PrivilegedExceptionAction) () -> { - InputStream is = null; - if (reloadFlag) { - URL url = classLoader.getResource(resourceName); - if (url != null) { - URLConnection connection = url.openConnection(); - if (connection != null) { - // Disable caches to get fresh data for - // reloading. - connection.setUseCaches(false); - is = connection.getInputStream(); - } - } - } else { - is = classLoader.getResourceAsStream(resourceName); - } - return is; - }); - } catch (PrivilegedActionException e) { - throw (IOException) e.getException(); - } - if (stream != null) { - try { - bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); - } finally { - stream.close(); - } + InputStream stream = getResourceInputStream(loader, resourceName, reload); + + if (stream != null) { + try (stream) { + bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); + } } } else { throw new IllegalArgumentException("unknown format: " + format); @@ -105,12 +79,34 @@ public ResourceBundle newBundle(String baseName, Locale locale, String format, C return bundle; } - private String toResourceName0(String bundleName, String suffix) { + private String toResourceName0(String bundleName) { // application protocol check if (bundleName.contains(SPILT)) { return null; } else { - return toResourceName(bundleName, suffix); + return toResourceName(bundleName, "properties"); } } + + private InputStream getResourceInputStream(ClassLoader classLoader, String resourceName, boolean reloadFlag) throws IOException { + + InputStream is = null; + + if (reloadFlag) { + URL url = classLoader.getResource(resourceName); + if (url != null) { + URLConnection connection = url.openConnection(); + if (connection != null) { + // Disable caches to get fresh data for reloading. + connection.setUseCaches(false); + is = connection.getInputStream(); + } + } + } else { + is = classLoader.getResourceAsStream(resourceName); + } + + return is; + } + } diff --git a/common/src/test/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8ControlTest.java b/common/src/test/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8ControlTest.java index 086b84a9e6c..43d4ecb2356 100644 --- a/common/src/test/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8ControlTest.java +++ b/common/src/test/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8ControlTest.java @@ -17,14 +17,59 @@ package org.apache.hertzbeat.common.support; +import java.io.IOException; +import java.util.Locale; +import java.util.ResourceBundle; + import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * Test case for {@link ResourceBundleUtf8Control} */ class ResourceBundleUtf8ControlTest { - @Test - void newBundle() { - } -} \ No newline at end of file + @Test + void testNewBundleWithPropertiesFormat() throws IllegalAccessException, InstantiationException, IOException { + + ResourceBundle.Control control = new ResourceBundleUtf8Control(); + ClassLoader loader = getClass().getClassLoader(); + String baseName = "msg"; + + ResourceBundle bundle = control.newBundle(baseName, Locale.ENGLISH, "java.properties", loader, false); + assertNotNull(bundle); + assertEquals("Hello, World!", bundle.getString("hello")); + + bundle = control.newBundle(baseName, Locale.ROOT, "java.properties", loader, false); + assertNotNull(bundle); + assertEquals("你好", bundle.getString("hello")); + } + + @Test + void testNewBundleWithClassFormat() throws IllegalAccessException, InstantiationException, IOException { + + ResourceBundle.Control control = new ResourceBundleUtf8Control(); + ClassLoader loader = getClass().getClassLoader(); + String baseName = "dummyClassBundle"; + + ResourceBundle bundle = control.newBundle(baseName, Locale.ENGLISH, "java.class", loader, false); + //because not have an actual class, bundle should be null + assertNull(bundle); + } + + @Test + void testReloading() throws IllegalAccessException, InstantiationException, IOException { + ResourceBundle.Control control = new ResourceBundleUtf8Control(); + ClassLoader loader = getClass().getClassLoader(); + String baseName = "msg"; + + // Test with reload flag + ResourceBundle bundle = control.newBundle(baseName, Locale.ENGLISH, "java.properties", loader, true); + assertNotNull(bundle); + assertEquals("Hello, World!", bundle.getString("hello")); + } + +} diff --git a/common/src/test/resources/msg.properties b/common/src/test/resources/msg.properties new file mode 100644 index 00000000000..5ab87e3b125 --- /dev/null +++ b/common/src/test/resources/msg.properties @@ -0,0 +1 @@ +hello=你好 diff --git a/common/src/test/resources/msg_en.properties b/common/src/test/resources/msg_en.properties new file mode 100644 index 00000000000..09e75e35bf3 --- /dev/null +++ b/common/src/test/resources/msg_en.properties @@ -0,0 +1 @@ +hello=Hello, World! \ No newline at end of file From 96b025ac8d20e1f68deacb0f1e84cfb68e7cb39e Mon Sep 17 00:00:00 2001 From: yuluo-yx Date: Wed, 17 Jul 2024 15:12:45 +0800 Subject: [PATCH 3/5] fix Signed-off-by: yuluo-yx --- common/src/test/resources/msg_en.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/test/resources/msg_en.properties b/common/src/test/resources/msg_en.properties index 09e75e35bf3..a74c93cc6b3 100644 --- a/common/src/test/resources/msg_en.properties +++ b/common/src/test/resources/msg_en.properties @@ -1 +1 @@ -hello=Hello, World! \ No newline at end of file +hello=Hello, World! From 3e7c9f3a7c0283f77fb68d5448c6f07537a49e3f Mon Sep 17 00:00:00 2001 From: yuluo-yx Date: Wed, 17 Jul 2024 22:37:41 +0800 Subject: [PATCH 4/5] chore: add license header Signed-off-by: yuluo-yx --- common/src/test/resources/msg.properties | 15 +++++++++++++++ common/src/test/resources/msg_en.properties | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/common/src/test/resources/msg.properties b/common/src/test/resources/msg.properties index 5ab87e3b125..6dc68e451d6 100644 --- a/common/src/test/resources/msg.properties +++ b/common/src/test/resources/msg.properties @@ -1 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + hello=你好 diff --git a/common/src/test/resources/msg_en.properties b/common/src/test/resources/msg_en.properties index a74c93cc6b3..7514bf5db7d 100644 --- a/common/src/test/resources/msg_en.properties +++ b/common/src/test/resources/msg_en.properties @@ -1 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + hello=Hello, World! From 8e97c502286b0e9f85845a2d579496db0ed1ead0 Mon Sep 17 00:00:00 2001 From: yuluo-yx Date: Wed, 17 Jul 2024 22:50:27 +0800 Subject: [PATCH 5/5] fix: fix code style Signed-off-by: yuluo-yx --- .../support/ResourceBundleUtf8Control.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java b/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java index 263327e40f9..a3065fb661c 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java +++ b/common/src/main/java/org/apache/hertzbeat/common/support/ResourceBundleUtf8Control.java @@ -41,6 +41,7 @@ public class ResourceBundleUtf8Control extends ResourceBundle.Control { @Override public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { + String bundleName = toBundleName(baseName, locale); ResourceBundle bundle = null; if (JAVA_CLASS.equals(format)) { @@ -58,20 +59,20 @@ public ResourceBundle newBundle(String baseName, Locale locale, String format, C + " cannot be cast to ResourceBundle"); } } catch (ClassNotFoundException ignored) {} - catch (InvocationTargetException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } else if (JAVA_PROPERTIES.equals(format)) { + catch (InvocationTargetException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + } else if (JAVA_PROPERTIES.equals(format)) { final String resourceName = toResourceName0(bundleName); if (resourceName == null) { return null; } - InputStream stream = getResourceInputStream(loader, resourceName, reload); + InputStream stream = getResourceInputStream(loader, resourceName, reload); - if (stream != null) { - try (stream) { - bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); - } + if (stream != null) { + try (stream) { + bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); + } } } else { throw new IllegalArgumentException("unknown format: " + format);