This is an automated email from the ASF dual-hosted git repository.

albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new a72123a  Add unit test for FrameworkModel/ApplicationModel/ModuleModel 
and add test case for ConfigManager (#9301)
a72123a is described below

commit a72123a3e2738c35847bfb96154f8e61845b906c
Author: 灼华 <[email protected]>
AuthorDate: Sun Nov 28 16:32:18 2021 +0800

    Add unit test for FrameworkModel/ApplicationModel/ModuleModel and add test 
case for ConfigManager (#9301)
    
    * Add unit test for FrameworkModel/ApplicationModel/ModuleModel and add 
test case for ConfigManager
    
    * FIX
---
 .../dubbo/common/lang/ShutdownHookCallbacks.java   |   2 +-
 .../common/resource/GlobalResourcesRepository.java |  16 ++-
 .../common/utils/ClassLoaderResourceLoader.java    |  16 ++-
 .../config/context/AbstractConfigManager.java      |  10 +-
 .../apache/dubbo/config/context/ConfigManager.java |   2 +-
 .../dubbo/config/context/ModuleConfigManager.java  |  11 +-
 .../org/apache/dubbo/rpc/model/ScopeModel.java     |   4 +
 .../common/config/ConfigurationCacheTest.java      |  35 +++++
 .../resource/GlobalResourcesRepositoryTest.java    |  77 +++++++++++
 .../utils/ClassLoaderResourceLoaderTest.java       |  58 ++++++++
 .../dubbo/config/context/ConfigManagerTest.java    |  96 +++++++++++++-
 .../dubbo/rpc/model/ApplicationModelTest.java      | 146 +++++++++++++++++++++
 .../apache/dubbo/rpc/model/FrameworkModelTest.java | 106 +++++++++++++++
 .../apache/dubbo/rpc/model/ModuleModelTest.java    |  89 +++++++++++++
 .../org/apache/dubbo/rpc/model/ScopeModelTest.java |   9 +-
 .../rpc/support/MockScopeModelDestroyListener.java |  39 ++++++
 16 files changed, 686 insertions(+), 30 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java
index da3f6a7..8665e9b 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java
@@ -27,7 +27,7 @@ import static java.util.Collections.sort;
 import static org.apache.dubbo.common.function.ThrowableAction.execute;
 
 /**
- * The compose {@link ShutdownHookCallback} class to manipulate one and more 
{@link ShutdownHookCallback} instances
+ * The composed {@link ShutdownHookCallback} class to manipulate one and more 
{@link ShutdownHookCallback} instances
  *
  * @since 2.7.5
  */
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/resource/GlobalResourcesRepository.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/resource/GlobalResourcesRepository.java
index 4f74ddc..7a309e6 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/resource/GlobalResourcesRepository.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/resource/GlobalResourcesRepository.java
@@ -87,7 +87,7 @@ public class GlobalResourcesRepository {
         return executorService;
     }
 
-    synchronized public void destroy() {
+    public synchronized void destroy() {
         if (logger.isInfoEnabled()) {
             logger.info("Destroying global resources ...");
         }
@@ -125,14 +125,24 @@ public class GlobalResourcesRepository {
      * Register a one-off disposable, the disposable is removed automatically 
on first shutdown.
      * @param disposable
      */
-    synchronized public void registerDisposable(Disposable disposable) {
+    public synchronized void registerDisposable(Disposable disposable) {
         if (!oneoffDisposables.contains(disposable)) {
             oneoffDisposables.add(disposable);
         }
     }
 
-    synchronized public void removeDisposable(Disposable disposable) {
+    public synchronized void removeDisposable(Disposable disposable) {
         this.oneoffDisposables.remove(disposable);
     }
 
+
+    // for test
+    public static List<Disposable> getGlobalReusedDisposables() {
+        return globalReusedDisposables;
+    }
+
+    // for test
+    public List<Disposable> getOneoffDisposables() {
+        return oneoffDisposables;
+    }
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoader.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoader.java
index 2fba54f..8266938 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoader.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoader.java
@@ -42,8 +42,8 @@ public class ClassLoaderResourceLoader {
         GlobalResourcesRepository.registerGlobalDisposable(()-> destroy());
     }
 
-    public static Map<ClassLoader, Set<java.net.URL>> loadResources(String 
fileName, List<ClassLoader> classLoaders) {
-        Map<ClassLoader, Set<java.net.URL>> resources = new 
ConcurrentHashMap<>();
+    public static Map<ClassLoader, Set<URL>> loadResources(String fileName, 
List<ClassLoader> classLoaders) {
+        Map<ClassLoader, Set<URL>> resources = new ConcurrentHashMap<>();
         CountDownLatch countDownLatch = new 
CountDownLatch(classLoaders.size());
         for (ClassLoader classLoader : classLoaders) {
             GlobalResourcesRepository.getGlobalExecutorService().submit(() -> {
@@ -59,8 +59,8 @@ public class ClassLoaderResourceLoader {
         return Collections.unmodifiableMap(new LinkedHashMap<>(resources));
     }
 
-    public static Set<java.net.URL> loadResources(String fileName, ClassLoader 
currentClassLoader) {
-        Map<ClassLoader, Map<String, Set<java.net.URL>>> classLoaderCache;
+    public static Set<URL> loadResources(String fileName, ClassLoader 
currentClassLoader) {
+        Map<ClassLoader, Map<String, Set<URL>>> classLoaderCache;
         if (classLoaderResourcesCache == null || (classLoaderCache = 
classLoaderResourcesCache.get()) == null) {
             synchronized (ClassLoaderResourceLoader.class) {
                 if (classLoaderResourcesCache == null || (classLoaderCache = 
classLoaderResourcesCache.get()) == null) {
@@ -72,9 +72,9 @@ public class ClassLoaderResourceLoader {
         if (!classLoaderCache.containsKey(currentClassLoader)) {
             classLoaderCache.putIfAbsent(currentClassLoader, new 
ConcurrentHashMap<>());
         }
-        Map<String, Set<java.net.URL>> urlCache = 
classLoaderCache.get(currentClassLoader);
+        Map<String, Set<URL>> urlCache = 
classLoaderCache.get(currentClassLoader);
         if (!urlCache.containsKey(fileName)) {
-            Set<java.net.URL> set = new LinkedHashSet<>();
+            Set<URL> set = new LinkedHashSet<>();
             Enumeration<URL> urls;
             try {
                 urls = currentClassLoader.getResources(fileName);
@@ -113,4 +113,8 @@ public class ClassLoaderResourceLoader {
     }
 
 
+    // for test
+    protected static SoftReference<Map<ClassLoader, Map<String, Set<URL>>>> 
getClassLoaderResourcesCache() {
+        return classLoaderResourcesCache;
+    }
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
index 282c18a..69c6771 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
@@ -327,7 +327,7 @@ public abstract class AbstractConfigManager extends 
LifecycleAdapter {
         if (configsMap.isEmpty()) {
             return null;
         }
-        // try find config by name
+        // try to find config by name
         if (ReflectUtils.hasMethod(cls, CONFIG_NAME_READ_METHOD)) {
             List<C> list = configsMap.values().stream()
                 .filter(cfg -> name.equals(getConfigName(cfg)))
@@ -344,7 +344,7 @@ public abstract class AbstractConfigManager extends 
LifecycleAdapter {
 
     private <C extends AbstractConfig> String getConfigName(C config) {
         try {
-            return (String) ReflectUtils.getProperty(config, 
CONFIG_NAME_READ_METHOD);
+            return ReflectUtils.getProperty(config, CONFIG_NAME_READ_METHOD);
         } catch (Exception e) {
             return null;
         }
@@ -463,7 +463,7 @@ public abstract class AbstractConfigManager extends 
LifecycleAdapter {
         Set<String> configIds = this.getConfigIdsFromProps(cls);
         configIds.forEach(id -> {
             if (!this.getConfig(cls, id).isPresent()) {
-                T config = null;
+                T config;
                 try {
                     config = createConfig(cls, scopeModel);
                     config.setId(id);
@@ -500,7 +500,7 @@ public abstract class AbstractConfigManager extends 
LifecycleAdapter {
             // load single config
             List<Map<String, String>> configurationMaps = 
environment.getConfigurationMaps();
             if (ConfigurationUtils.hasSubProperties(configurationMaps, 
AbstractConfig.getTypePrefix(cls))) {
-                T config = null;
+                T config;
                 try {
                     config = createConfig(cls, scopeModel);
                     config.refresh();
@@ -560,7 +560,7 @@ public abstract class AbstractConfigManager extends 
LifecycleAdapter {
             throw new IllegalStateException("Add default config failed: " + 
configType.getSimpleName(), e);
         }
 
-        //validate configs
+        // validate configs
         Collection<T> configs = this.getConfigs(configType);
         if (getConfigValidator() != null) {
             for (T config : configs) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java 
b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
index 2d6de5f..a6f4484 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
@@ -219,7 +219,7 @@ public class ConfigManager extends AbstractConfigManager 
implements ApplicationE
 
     @Override
     public void refreshAll() {
-        // refresh all configs here,
+        // refresh all configs here
         getApplication().ifPresent(ApplicationConfig::refresh);
         getMonitor().ifPresent(MonitorConfig::refresh);
         getMetrics().ifPresent(MetricsConfig::refresh);
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java
index c8c802a..a935a88 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java
@@ -168,18 +168,13 @@ public class ModuleConfigManager extends 
AbstractConfigManager {
 
     @Override
     public void refreshAll() {
-        // refresh all configs here,
+        // refresh all configs here
         getModule().ifPresent(ModuleConfig::refresh);
         getProviders().forEach(ProviderConfig::refresh);
         getConsumers().forEach(ConsumerConfig::refresh);
 
-        for (ReferenceConfigBase<?> reference : getReferences()) {
-            reference.refresh();
-        }
-
-        for (ServiceConfigBase sc : getServices()) {
-            sc.refresh();
-        }
+        getReferences().forEach(ReferenceConfigBase::refresh);
+        getServices().forEach(ServiceConfigBase::refresh);
     }
 
     @Override
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java 
b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
index 042fc5b..dd4becb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
@@ -167,6 +167,10 @@ public abstract class ScopeModel implements 
ExtensionAccessor {
         return parent;
     }
 
+    public ExtensionScope getScope() {
+        return scope;
+    }
+
     public void addClassLoader(ClassLoader classLoader) {
         this.classLoaders.add(classLoader);
         if (parent != null) {
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationCacheTest.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationCacheTest.java
new file mode 100644
index 0000000..e4a5aca
--- /dev/null
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationCacheTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+package org.apache.dubbo.common.config;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * {@link ConfigurationCache}
+ */
+public class ConfigurationCacheTest {
+
+    @Test
+    public void test() {
+        ConfigurationCache configurationCache = new ConfigurationCache();
+        String value = configurationCache.computeIfAbsent("k1", k -> "v1");
+        Assertions.assertEquals(value, "v1");
+        value = configurationCache.computeIfAbsent("k1", k -> "v2");
+        Assertions.assertEquals(value, "v1");
+    }
+}
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/common/resource/GlobalResourcesRepositoryTest.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/common/resource/GlobalResourcesRepositoryTest.java
new file mode 100644
index 0000000..28ce084
--- /dev/null
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/common/resource/GlobalResourcesRepositoryTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.dubbo.common.resource;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * {@link GlobalResourcesRepository}
+ */
+public class GlobalResourcesRepositoryTest {
+
+    @Test
+    public void test() throws NoSuchFieldException {
+        GlobalResourcesRepository repository = 
GlobalResourcesRepository.getInstance();
+
+        ExecutorService globalExecutorService = 
GlobalResourcesRepository.getGlobalExecutorService();
+        Assertions.assertNotNull(globalExecutorService);
+
+        GlobalDisposable globalDisposable = new GlobalDisposable();
+        GlobalResourcesRepository.registerGlobalDisposable(globalDisposable);
+
+        OneOffDisposable oneOffDisposable = new OneOffDisposable();
+        repository.registerDisposable(oneOffDisposable);
+
+        repository.destroy();
+        Assertions.assertTrue(globalExecutorService.isShutdown());
+        Assertions.assertTrue(globalDisposable.isDestroyed());
+        Assertions.assertTrue(oneOffDisposable.isDestroyed());
+        
Assertions.assertTrue(!GlobalResourcesRepository.getGlobalReusedDisposables().isEmpty());
+        
Assertions.assertTrue(GlobalResourcesRepository.getGlobalReusedDisposables().contains(globalDisposable));
+        Assertions.assertTrue(repository.getOneoffDisposables().isEmpty());
+    }
+
+    class GlobalDisposable implements Disposable {
+
+        boolean destroyed = false;
+
+        @Override
+        public void destroy() {
+            destroyed = true;
+        }
+
+        public boolean isDestroyed() {
+            return destroyed;
+        }
+    }
+
+    class OneOffDisposable implements Disposable {
+        boolean destroyed = false;
+
+        @Override
+        public void destroy() {
+            destroyed = true;
+        }
+
+        public boolean isDestroyed() {
+            return destroyed;
+        }
+    }
+}
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoaderTest.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoaderTest.java
new file mode 100644
index 0000000..10331e8
--- /dev/null
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoaderTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package org.apache.dubbo.common.utils;
+
+import org.apache.dubbo.common.extension.DubboInternalLoadingStrategy;
+import org.apache.dubbo.common.extension.director.FooAppProvider;
+import org.apache.dubbo.common.resource.GlobalResourcesRepository;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * {@link ClassLoaderResourceLoader}
+ */
+public class ClassLoaderResourceLoaderTest {
+
+    @Test
+    public void test() {
+        DubboInternalLoadingStrategy dubboInternalLoadingStrategy = new 
DubboInternalLoadingStrategy();
+        String directory = dubboInternalLoadingStrategy.directory();
+        String type = FooAppProvider.class.getName();
+        String fileName = directory + type;
+
+        ClassLoader contextClassLoader = 
Thread.currentThread().getContextClassLoader();
+        Map<ClassLoader, Set<URL>> loadResources = 
ClassLoaderResourceLoader.loadResources(fileName, 
Arrays.asList(contextClassLoader));
+        Assertions.assertTrue(loadResources.containsKey(contextClassLoader));
+        
Assertions.assertTrue(!loadResources.get(contextClassLoader).isEmpty());
+
+        // cache
+        
Assertions.assertNotNull(ClassLoaderResourceLoader.getClassLoaderResourcesCache());
+        loadResources = ClassLoaderResourceLoader.loadResources(fileName, 
Arrays.asList(contextClassLoader));
+        Assertions.assertTrue(loadResources.containsKey(contextClassLoader));
+        
Assertions.assertTrue(!loadResources.get(contextClassLoader).isEmpty());
+
+        
Assertions.assertNotNull(GlobalResourcesRepository.getGlobalReusedDisposables());
+
+        ClassLoaderResourceLoader.destroy();
+        
Assertions.assertNull(ClassLoaderResourceLoader.getClassLoaderResourcesCache());
+    }
+}
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
index 8e50939..321343c 100644
--- 
a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import java.util.Collection;
+import java.util.Optional;
 
 import static java.util.Arrays.asList;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
@@ -43,7 +44,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
+ * {@link AbstractConfigManager} Test
  * {@link ConfigManager} Test
+ * {@link ModuleConfigManager} Test
  *
  * @since 2.7.5
  */
@@ -119,7 +122,7 @@ public class ConfigManagerTest {
         assertEquals(monitorConfig, moduleConfigManager.getMonitor().get());
     }
 
-    // Test MonitorConfig correlative methods
+    // Test ModuleConfig correlative methods
     @Test
     public void testModuleConfig() {
         ModuleConfig config = new ModuleConfig();
@@ -306,4 +309,95 @@ public class ConfigManagerTest {
             System.clearProperty(DUBBO_CONFIG_MODE);
         }
     }
+
+    @Test
+    public void testGetConfigByIdOrName() {
+        RegistryConfig registryConfig = new RegistryConfig();
+        registryConfig.setId("registryID_1");
+        configManager.addRegistry(registryConfig);
+        Optional<RegistryConfig> registryConfigOptional = 
configManager.getConfig(RegistryConfig.class, registryConfig.getId());
+        Assertions.assertEquals(registryConfigOptional.get(), registryConfig);
+
+
+        ProtocolConfig protocolConfig = new ProtocolConfig("dubbo");
+        configManager.addProtocol(protocolConfig);
+        Optional<ProtocolConfig> protocolConfigOptional = 
configManager.getConfig(ProtocolConfig.class, protocolConfig.getName());
+        Assertions.assertEquals(protocolConfigOptional.get(), protocolConfig);
+
+        ModuleConfig moduleConfig = new ModuleConfig();
+        moduleConfig.setId("moduleID_1");
+        moduleConfigManager.setModule(moduleConfig);
+        Optional<ModuleConfig> moduleConfigOptional = 
moduleConfigManager.getConfig(ModuleConfig.class, moduleConfig.getId());
+        Assertions.assertEquals(moduleConfigOptional.get(), moduleConfig);
+
+        Optional<RegistryConfig> config = 
moduleConfigManager.getConfig(RegistryConfig.class, registryConfig.getId());
+        Assertions.assertEquals(config.get(), registryConfig);
+    }
+
+    @Test
+    public void testLoadConfigsOfTypeFromProps() {
+        try {
+            // dubbo.application.enable-file-cache = false
+            configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);
+            Optional<ApplicationConfig> application = 
configManager.getApplication();
+            Assertions.assertTrue(application.isPresent());
+            configManager.removeConfig(application.get());
+
+            System.setProperty("dubbo.protocols.dubbo1.port", "20880");
+            System.setProperty("dubbo.protocols.dubbo2.port", "20881");
+            System.setProperty("dubbo.protocols.rest1.port", "8080");
+            System.setProperty("dubbo.protocols.rest2.port", "8081");
+            configManager.loadConfigsOfTypeFromProps(ProtocolConfig.class);
+            Collection<ProtocolConfig> protocols = 
configManager.getProtocols();
+            Assertions.assertEquals(protocols.size(), 4);
+
+            System.setProperty("dubbo.applications.app1.name", "app-demo1");
+            System.setProperty("dubbo.applications.app2.name", "app-demo2");
+            try {
+                
configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);
+                Assertions.fail();
+            } catch (Exception e) {
+                Assertions.assertTrue(e.getMessage().contains("load config 
failed"));
+            }
+        } finally {
+            System.clearProperty("dubbo.protocols.dubbo1.port");
+            System.clearProperty("dubbo.protocols.dubbo2.port");
+            System.clearProperty("dubbo.protocols.rest1.port");
+            System.clearProperty("dubbo.protocols.rest2.port");
+            System.clearProperty("dubbo.applications.app1.name");
+            System.clearProperty("dubbo.applications.app2.name");
+        }
+
+    }
+
+    @Test
+    public void testLoadConfig() {
+        configManager.loadConfigs();
+        Assertions.assertTrue(configManager.getApplication().isPresent());
+        Assertions.assertTrue(configManager.getSsl().isPresent());
+        Assertions.assertFalse(configManager.getProtocols().isEmpty());
+
+        int port = 20880;
+        ProtocolConfig config1 = new ProtocolConfig();
+        config1.setName("dubbo");
+        config1.setPort(port);
+
+        ProtocolConfig config2 = new ProtocolConfig();
+        config2.setName("rest");
+        config2.setPort(port);
+        configManager.addProtocols(asList(config1, config2));
+        try {
+            configManager.loadConfigs();
+            Assertions.fail();
+        } catch (Exception e) {
+            Assertions.assertTrue(e instanceof IllegalStateException);
+            Assertions.assertTrue(e.getMessage().contains("Duplicated port 
used by protocol configs, port: " + port));
+        }
+
+        moduleConfigManager.loadConfigs();
+        Assertions.assertTrue(moduleConfigManager.getModule().isPresent());
+        Assertions.assertFalse(moduleConfigManager.getProviders().isEmpty());
+        Assertions.assertFalse(moduleConfigManager.getConsumers().isEmpty());
+
+    }
 }
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ApplicationModelTest.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ApplicationModelTest.java
new file mode 100644
index 0000000..b42a39b
--- /dev/null
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ApplicationModelTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+package org.apache.dubbo.rpc.model;
+
+import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.common.config.ConfigurationCache;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
+import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.rpc.support.MockScopeModelDestroyListener;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * {@link ApplicationModel}
+ */
+public class ApplicationModelTest {
+
+    @Test
+    public void testInitialize() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+        ApplicationModel applicationModel = new 
ApplicationModel(frameworkModel);
+
+        Assertions.assertEquals(applicationModel.getParent(), frameworkModel);
+        Assertions.assertEquals(applicationModel.getScope(), 
ExtensionScope.APPLICATION);
+        Assertions.assertEquals(applicationModel.getFrameworkModel(), 
frameworkModel);
+        Assertions.assertFalse(applicationModel.isInternal());
+        
Assertions.assertTrue(frameworkModel.getApplicationModels().contains(applicationModel));
+        Assertions.assertNotNull(applicationModel.getInternalId());
+
+        Assertions.assertNotNull(applicationModel.getExtensionDirector());
+        Assertions.assertNotNull(applicationModel.getBeanFactory());
+        
Assertions.assertTrue(applicationModel.getClassLoaders().contains(ScopeModel.class.getClassLoader()));
+
+        Assertions.assertNotNull(applicationModel.getInternalModule());
+        
Assertions.assertNotNull(applicationModel.getApplicationServiceRepository());
+
+        ScopeBeanFactory applicationModelBeanFactory = 
applicationModel.getBeanFactory();
+        
Assertions.assertNotNull(applicationModelBeanFactory.getBean(ShutdownHookCallbacks.class));
+        
Assertions.assertNotNull(applicationModelBeanFactory.getBean(FrameworkStatusReportService.class));
+        
Assertions.assertNotNull(applicationModelBeanFactory.getBean(ConfigurationCache.class));
+
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testDefaultApplication() {
+        ApplicationModel applicationModel = ApplicationModel.defaultModel();
+        FrameworkModel frameworkModel = applicationModel.getFrameworkModel();
+
+        Assertions.assertFalse(applicationModel.isInternal());
+        Assertions.assertEquals(frameworkModel.defaultApplication(), 
applicationModel);
+        
Assertions.assertTrue(frameworkModel.getApplicationModels().contains(applicationModel));
+
+        String desc = applicationModel.getDesc();
+        Assertions.assertEquals(desc, "Dubbo Application[" + 
applicationModel.getInternalId() + "](unknown)");
+
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testModule() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+        ApplicationModel applicationModel = new 
ApplicationModel(frameworkModel);
+
+        ModuleModel defaultModule = applicationModel.getDefaultModule();
+        ModuleModel internalModule = applicationModel.getInternalModule();
+
+        
Assertions.assertTrue(applicationModel.getModuleModels().contains(defaultModule));
+        
Assertions.assertTrue(applicationModel.getModuleModels().contains(internalModule));
+        
Assertions.assertTrue(applicationModel.getPubModuleModels().contains(defaultModule));
+        
Assertions.assertFalse(applicationModel.getPubModuleModels().contains(internalModule));
+
+        applicationModel.removeModule(defaultModule);
+        
Assertions.assertFalse(applicationModel.getModuleModels().contains(defaultModule));
+        
Assertions.assertFalse(applicationModel.getPubModuleModels().contains(defaultModule));
+
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testOfNullable() {
+        ApplicationModel applicationModel = ApplicationModel.ofNullable(null);
+        Assertions.assertEquals(ApplicationModel.defaultModel(), 
applicationModel);
+        applicationModel.getFrameworkModel().destroy();
+
+        FrameworkModel frameworkModel = new FrameworkModel();
+        ApplicationModel applicationModel1 = new 
ApplicationModel(frameworkModel);
+        ApplicationModel applicationModel2 = 
ApplicationModel.ofNullable(applicationModel1);
+        Assertions.assertEquals(applicationModel1, applicationModel2);
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testDestroy() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+        ApplicationModel applicationModel = new 
ApplicationModel(frameworkModel);
+
+        applicationModel.getDefaultModule();
+        applicationModel.newModule();
+
+        MockScopeModelDestroyListener destroyListener = new 
MockScopeModelDestroyListener();
+        applicationModel.addDestroyListener(destroyListener);
+        applicationModel.destroy();
+
+        
Assertions.assertFalse(frameworkModel.getApplicationModels().contains(applicationModel));
+        Assertions.assertTrue(applicationModel.getModuleModels().isEmpty());
+        Assertions.assertTrue(destroyListener.isDestroyed());
+        Assertions.assertEquals(destroyListener.getScopeModel(), 
applicationModel);
+        
Assertions.assertNull(applicationModel.getApplicationServiceRepository());
+        Assertions.assertTrue(applicationModel.isDestroyed());
+        // trigger frameworkModel.tryDestroy()
+        Assertions.assertTrue(frameworkModel.isDestroyed());
+
+        try {
+            applicationModel.getDefaultModule();
+            Assertions.fail("Cannot create new module after application model 
destroyed");
+        } catch (Exception e) {
+            Assertions.assertEquals("ApplicationModel is destroyed", 
e.getMessage(), StringUtils.toString(e));
+        }
+
+        try {
+            applicationModel.newModule();
+            Assertions.fail("Cannot create new module after application model 
destroyed");
+        } catch (Exception e) {
+            Assertions.assertEquals("ApplicationModel is destroyed", 
e.getMessage(), StringUtils.toString(e));
+        }
+
+    }
+
+}
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/FrameworkModelTest.java 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/FrameworkModelTest.java
new file mode 100644
index 0000000..9967d57
--- /dev/null
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/FrameworkModelTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package org.apache.dubbo.rpc.model;
+
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * {@link FrameworkModel}
+ */
+public class FrameworkModelTest {
+    @Test
+    public void testInitialize() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+
+        Assertions.assertNull(frameworkModel.getParent());
+        Assertions.assertEquals(frameworkModel.getScope(), 
ExtensionScope.FRAMEWORK);
+
+        Assertions.assertNotNull(frameworkModel.getInternalId());
+        
Assertions.assertTrue(FrameworkModel.getAllInstances().contains(frameworkModel));
+        Assertions.assertEquals(FrameworkModel.defaultModel(), frameworkModel);
+
+        Assertions.assertNotNull(frameworkModel.getExtensionDirector());
+        Assertions.assertNotNull(frameworkModel.getBeanFactory());
+        
Assertions.assertTrue(frameworkModel.getClassLoaders().contains(ScopeModel.class.getClassLoader()));
+
+        Assertions.assertNotNull(frameworkModel.getServiceRepository());
+        ApplicationModel applicationModel = 
frameworkModel.getInternalApplicationModel();
+        Assertions.assertNotNull(applicationModel);
+        
Assertions.assertTrue(frameworkModel.getAllApplicationModels().contains(applicationModel));
+        
Assertions.assertFalse(frameworkModel.getApplicationModels().contains(applicationModel));
+
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testDefaultModel() {
+        FrameworkModel frameworkModel = FrameworkModel.defaultModel();
+        
Assertions.assertTrue(FrameworkModel.getAllInstances().contains(frameworkModel));
+        String desc = frameworkModel.getDesc();
+        Assertions.assertEquals(desc, "Dubbo Framework[" + 
frameworkModel.getInternalId() + "]");
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testApplicationModel() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+
+        ApplicationModel applicationModel = 
frameworkModel.defaultApplication();
+        ApplicationModel internalApplicationModel = 
frameworkModel.getInternalApplicationModel();
+
+        Assertions.assertEquals(frameworkModel.getDefaultAppModel(), 
applicationModel);
+        
Assertions.assertTrue(frameworkModel.getAllApplicationModels().contains(applicationModel));
+        
Assertions.assertTrue(frameworkModel.getAllApplicationModels().contains(internalApplicationModel));
+        
Assertions.assertTrue(frameworkModel.getApplicationModels().contains(applicationModel));
+        
Assertions.assertFalse(frameworkModel.getApplicationModels().contains(internalApplicationModel));
+
+        frameworkModel.removeApplication(applicationModel);
+        
Assertions.assertFalse(frameworkModel.getAllApplicationModels().contains(applicationModel));
+        
Assertions.assertFalse(frameworkModel.getApplicationModels().contains(applicationModel));
+
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void destroyAll() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+        frameworkModel.defaultApplication();
+        frameworkModel.newApplication();
+
+        FrameworkModel.destroyAll();
+        Assertions.assertTrue(FrameworkModel.getAllInstances().isEmpty());
+        Assertions.assertTrue(frameworkModel.isDestroyed());
+
+        try {
+            frameworkModel.defaultApplication();
+            Assertions.fail("Cannot create new application after framework 
model destroyed");
+        } catch (Exception e) {
+            Assertions.assertEquals("FrameworkModel is destroyed", 
e.getMessage(), StringUtils.toString(e));
+        }
+
+        try {
+            frameworkModel.newApplication();
+            Assertions.fail("Cannot create new application after framework 
model destroyed");
+        } catch (Exception e) {
+            Assertions.assertEquals("FrameworkModel is destroyed", 
e.getMessage(), StringUtils.toString(e));
+        }
+    }
+
+}
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java
new file mode 100644
index 0000000..75366f5
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+package org.apache.dubbo.rpc.model;
+
+import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.common.config.ConfigurationCache;
+import org.apache.dubbo.common.config.ModuleEnvironment;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.rpc.support.MockScopeModelDestroyListener;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * {@link ModuleModel}
+ */
+public class ModuleModelTest {
+
+    @Test
+    public void testInitialize() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+        ApplicationModel applicationModel = new 
ApplicationModel(frameworkModel);
+        ModuleModel moduleModel = new ModuleModel(applicationModel);
+        Assertions.assertEquals(moduleModel.getParent(), applicationModel);
+        Assertions.assertEquals(moduleModel.getScope(), ExtensionScope.MODULE);
+        Assertions.assertEquals(moduleModel.getApplicationModel(), 
applicationModel);
+        
Assertions.assertTrue(applicationModel.getPubModuleModels().contains(moduleModel));
+        Assertions.assertNotNull(moduleModel.getInternalId());
+
+        Assertions.assertNotNull(moduleModel.getExtensionDirector());
+        Assertions.assertNotNull(moduleModel.getBeanFactory());
+        
Assertions.assertTrue(moduleModel.getClassLoaders().contains(ScopeModel.class.getClassLoader()));
+
+        Assertions.assertNotNull(moduleModel.getServiceRepository());
+        Assertions.assertNotNull(moduleModel.getConfigManager());
+
+        ScopeBeanFactory moduleModelBeanFactory = moduleModel.getBeanFactory();
+        
Assertions.assertNotNull(moduleModelBeanFactory.getBean(ConfigurationCache.class));
+
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testModelEnvironment() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+        ApplicationModel applicationModel = new 
ApplicationModel(frameworkModel);
+        ModuleModel moduleModel = new ModuleModel(applicationModel);
+
+        ModuleEnvironment modelEnvironment = moduleModel.getModelEnvironment();
+        Assertions.assertNotNull(modelEnvironment);
+
+        frameworkModel.destroy();
+    }
+
+    @Test
+    public void testDestroy() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+        ApplicationModel applicationModel = new 
ApplicationModel(frameworkModel);
+        ModuleModel moduleModel = new ModuleModel(applicationModel);
+
+        MockScopeModelDestroyListener destroyListener = new 
MockScopeModelDestroyListener();
+        moduleModel.addDestroyListener(destroyListener);
+
+        moduleModel.destroy();
+        Assertions.assertTrue(destroyListener.isDestroyed());
+        Assertions.assertEquals(destroyListener.getScopeModel(), moduleModel);
+        
Assertions.assertFalse(applicationModel.getPubModuleModels().contains(moduleModel));
+        Assertions.assertNull(moduleModel.getServiceRepository());
+        Assertions.assertTrue(moduleModel.isDestroyed());
+
+        // trigger tryDestroy
+        Assertions.assertTrue(applicationModel.isDestroyed());
+        Assertions.assertTrue(frameworkModel.isDestroyed());
+
+    }
+}
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ScopeModelTest.java 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ScopeModelTest.java
index dd9608d..f450586 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ScopeModelTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ScopeModelTest.java
@@ -32,21 +32,20 @@ public class ScopeModelTest {
         FrameworkModel.destroyAll();
 
         FrameworkModel frameworkModel = new FrameworkModel();
-        ApplicationModel applicationModel1 = frameworkModel.newApplication();
-        ApplicationModel applicationModel2 = frameworkModel.newApplication();
+        ApplicationModel applicationModel = frameworkModel.newApplication();
 
         List<Throwable> errors = new ArrayList<>();
-        applicationModel1.addDestroyListener(scopeModel -> {
+        applicationModel.addDestroyListener(scopeModel -> {
             try {
                 try {
-                    applicationModel1.getDefaultModule();
+                    applicationModel.getDefaultModule();
                     Assertions.fail("Cannot create new module after 
application model destroyed");
                 } catch (Exception e) {
                     Assertions.assertEquals("ApplicationModel is destroyed", 
e.getMessage(), StringUtils.toString(e));
                 }
 
                 try {
-                    applicationModel1.newModule();
+                    applicationModel.newModule();
                     Assertions.fail("Cannot create new module after 
application model destroyed");
                 } catch (Exception e) {
                     Assertions.assertEquals("ApplicationModel is destroyed", 
e.getMessage(), StringUtils.toString(e));
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/rpc/support/MockScopeModelDestroyListener.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/support/MockScopeModelDestroyListener.java
new file mode 100644
index 0000000..f89771d
--- /dev/null
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/support/MockScopeModelDestroyListener.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package org.apache.dubbo.rpc.support;
+
+import org.apache.dubbo.rpc.model.ScopeModel;
+import org.apache.dubbo.rpc.model.ScopeModelDestroyListener;
+
+public class MockScopeModelDestroyListener implements 
ScopeModelDestroyListener {
+    private boolean destroyed = false;
+    private ScopeModel scopeModel;
+
+    @Override
+    public void onDestroy(ScopeModel scopeModel) {
+        this.destroyed = true;
+        this.scopeModel = scopeModel;
+    }
+
+    public boolean isDestroyed() {
+        return destroyed;
+    }
+
+    public ScopeModel getScopeModel() {
+        return scopeModel;
+    }
+}

Reply via email to