Skip to content

Commit df69b5a

Browse files
authored
Merge pull request #597 from KamToHung/master
优化ContextManagerHelper异常处理,新增单元测试
2 parents 2498839 + 197cbb9 commit df69b5a

4 files changed

Lines changed: 442 additions & 2 deletions

File tree

common/src/main/java/org/dromara/dynamictp/common/manager/ContextManagerHelper.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class ContextManagerHelper {
3737
contextManager = ExtensionServiceLoader.getFirst(ContextManager.class);
3838
if (contextManager == null) {
3939
contextManager = new NullContextManager();
40-
throw new IllegalStateException("No ContextManager implementation found");
40+
log.warn("No ContextManager implementation found, fallback to NullContextManager.");
4141
}
4242
}
4343

@@ -69,4 +69,3 @@ public static String getEnvironmentProperty(String key, String defaultValue) {
6969
return contextManager.getEnvironmentProperty(key, defaultValue);
7070
}
7171
}
72-
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.dromara.dynamictp.test.common.manager;
19+
20+
import org.dromara.dynamictp.common.manager.ContextManagerHelper;
21+
import org.junit.jupiter.api.Assertions;
22+
import org.junit.jupiter.api.Test;
23+
24+
/**
25+
* ContextManagerHelperTest related.
26+
*/
27+
class ContextManagerHelperTest {
28+
29+
@Test
30+
void testFallbackToNullContextManagerWhenNoImplementationFound() {
31+
Assertions.assertNull(ContextManagerHelper.getBean(Object.class));
32+
Assertions.assertNull(ContextManagerHelper.getBean("bean", Object.class));
33+
Assertions.assertTrue(ContextManagerHelper.getBeansOfType(Object.class).isEmpty());
34+
Assertions.assertNull(ContextManagerHelper.getEnvironment());
35+
Assertions.assertNull(ContextManagerHelper.getEnvironmentProperty("key"));
36+
Assertions.assertNull(ContextManagerHelper.getEnvironmentProperty("key", new Object()));
37+
Assertions.assertNull(ContextManagerHelper.getEnvironmentProperty("key", "default"));
38+
}
39+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.dromara.dynamictp.test.core.notify.invoker;
19+
20+
import org.dromara.dynamictp.common.em.NotifyItemEnum;
21+
import org.dromara.dynamictp.common.entity.NotifyItem;
22+
import org.dromara.dynamictp.common.entity.NotifyPlatform;
23+
import org.dromara.dynamictp.common.entity.TpMainFields;
24+
import org.dromara.dynamictp.common.properties.DtpProperties;
25+
import org.dromara.dynamictp.core.handler.NotifierHandler;
26+
import org.dromara.dynamictp.core.notifier.DtpNotifier;
27+
import org.dromara.dynamictp.core.notifier.alarm.AlarmCounter;
28+
import org.dromara.dynamictp.core.notifier.chain.invoker.AlarmInvoker;
29+
import org.dromara.dynamictp.core.notifier.context.AlarmCtx;
30+
import org.dromara.dynamictp.core.notifier.context.DtpNotifyCtxHolder;
31+
import org.dromara.dynamictp.core.support.ExecutorWrapper;
32+
import org.dromara.dynamictp.spring.holder.SpringContextHolder;
33+
import org.junit.jupiter.api.AfterEach;
34+
import org.junit.jupiter.api.BeforeEach;
35+
import org.junit.jupiter.api.Test;
36+
import org.junit.jupiter.api.parallel.Execution;
37+
import org.junit.jupiter.api.parallel.ExecutionMode;
38+
import org.springframework.context.ApplicationContext;
39+
import org.springframework.context.support.GenericApplicationContext;
40+
41+
import java.lang.reflect.Constructor;
42+
import java.lang.reflect.Field;
43+
import java.util.Collections;
44+
import java.util.List;
45+
import java.util.Map;
46+
import java.util.concurrent.LinkedBlockingQueue;
47+
import java.util.concurrent.ThreadPoolExecutor;
48+
import java.util.concurrent.TimeUnit;
49+
50+
import static org.junit.jupiter.api.Assertions.assertEquals;
51+
import static org.junit.jupiter.api.Assertions.assertNull;
52+
import static org.junit.jupiter.api.Assertions.assertSame;
53+
import static org.junit.jupiter.api.Assertions.assertThrows;
54+
55+
/**
56+
* AlarmInvoker test.
57+
*
58+
* @author codex
59+
*/
60+
@Execution(ExecutionMode.SAME_THREAD)
61+
class AlarmInvokerTest {
62+
63+
private static final String PLATFORM_TYPE = "test_alarm_invoker";
64+
65+
private Map<String, DtpNotifier> notifiers;
66+
67+
private DtpProperties properties;
68+
69+
private GenericApplicationContext context;
70+
71+
private ApplicationContext originalContext;
72+
73+
private ThreadPoolExecutor executor;
74+
75+
@BeforeEach
76+
void setUp() throws Exception {
77+
notifiers = notifiers();
78+
properties = newProperties();
79+
originalContext = springContext();
80+
context = new GenericApplicationContext();
81+
context.getBeanFactory().registerSingleton("dtpProperties", properties);
82+
context.refresh();
83+
new SpringContextHolder().setApplicationContext(context);
84+
executor = new ThreadPoolExecutor(
85+
1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
86+
}
87+
88+
@AfterEach
89+
void tearDown() throws Exception {
90+
notifiers.remove(PLATFORM_TYPE);
91+
DtpNotifyCtxHolder.remove();
92+
executor.shutdownNow();
93+
context.close();
94+
setSpringContext(originalContext);
95+
}
96+
97+
@Test
98+
void testInvokeSendsAlarmResetsCounterAndClearsContext() {
99+
RecordingNotifier notifier = new RecordingNotifier();
100+
NotifyItem notifyItem = notifyItem(NotifyItemEnum.REJECT);
101+
String poolName = "alarm-invoker-success";
102+
properties.setPlatforms(Collections.singletonList(platform()));
103+
notifiers.put(PLATFORM_TYPE, notifier);
104+
AlarmCounter.initAlarmCounter(poolName, notifyItem);
105+
AlarmCounter.incAlarmCount(poolName, notifyItem.getType());
106+
AlarmCounter.incAlarmCount(poolName, notifyItem.getType());
107+
108+
new AlarmInvoker().invoke(new AlarmCtx(new ExecutorWrapper(poolName, executor), notifyItem));
109+
110+
assertEquals(NotifyItemEnum.REJECT, notifier.notifyItemEnum);
111+
assertEquals(0, AlarmCounter.getAlarmInfo(poolName, notifyItem.getType()).getCount());
112+
assertEquals(platform().getPlatformId(), notifier.platform.getPlatformId());
113+
assertNull(DtpNotifyCtxHolder.get());
114+
}
115+
116+
@Test
117+
void testInvokeClearsContextWhenSendAlarmFails() {
118+
NotifyItem notifyItem = notifyItem(NotifyItemEnum.REJECT);
119+
String poolName = "alarm-invoker-fail";
120+
properties.setPlatforms(Collections.singletonList(platform()));
121+
notifiers.put(PLATFORM_TYPE, new FailingNotifier());
122+
AlarmCounter.initAlarmCounter(poolName, notifyItem);
123+
124+
assertThrows(IllegalStateException.class,
125+
() -> new AlarmInvoker().invoke(new AlarmCtx(new ExecutorWrapper(poolName, executor), notifyItem)));
126+
127+
assertNull(DtpNotifyCtxHolder.get());
128+
}
129+
130+
private NotifyItem notifyItem(NotifyItemEnum notifyItemEnum) {
131+
NotifyItem notifyItem = new NotifyItem();
132+
notifyItem.setType(notifyItemEnum.getValue());
133+
notifyItem.setPlatformIds(Collections.singletonList("alarm-invoker-platform"));
134+
notifyItem.setPeriod(120);
135+
return notifyItem;
136+
}
137+
138+
private NotifyPlatform platform() {
139+
NotifyPlatform platform = new NotifyPlatform();
140+
platform.setPlatformId("alarm-invoker-platform");
141+
platform.setPlatform(PLATFORM_TYPE.toUpperCase());
142+
return platform;
143+
}
144+
145+
@SuppressWarnings("unchecked")
146+
private Map<String, DtpNotifier> notifiers() throws Exception {
147+
Field field = NotifierHandler.class.getDeclaredField("NOTIFIERS");
148+
field.setAccessible(true);
149+
return (Map<String, DtpNotifier>) field.get(null);
150+
}
151+
152+
private DtpProperties newProperties() throws Exception {
153+
Constructor<DtpProperties> constructor = DtpProperties.class.getDeclaredConstructor();
154+
constructor.setAccessible(true);
155+
return constructor.newInstance();
156+
}
157+
158+
private ApplicationContext springContext() throws Exception {
159+
Field field = SpringContextHolder.class.getDeclaredField("context");
160+
field.setAccessible(true);
161+
return (ApplicationContext) field.get(null);
162+
}
163+
164+
private void setSpringContext(ApplicationContext applicationContext) throws Exception {
165+
Field field = SpringContextHolder.class.getDeclaredField("context");
166+
field.setAccessible(true);
167+
field.set(null, applicationContext);
168+
}
169+
170+
private static class RecordingNotifier implements DtpNotifier {
171+
172+
private NotifyPlatform platform;
173+
174+
private NotifyItemEnum notifyItemEnum;
175+
176+
@Override
177+
public String platform() {
178+
return PLATFORM_TYPE;
179+
}
180+
181+
@Override
182+
public void sendChangeMsg(NotifyPlatform notifyPlatform, TpMainFields oldFields, List<String> diffs) {
183+
throw new UnsupportedOperationException();
184+
}
185+
186+
@Override
187+
public void sendAlarmMsg(NotifyPlatform notifyPlatform, NotifyItemEnum notifyItemEnum) {
188+
this.platform = notifyPlatform;
189+
this.notifyItemEnum = notifyItemEnum;
190+
}
191+
}
192+
193+
private static class FailingNotifier extends RecordingNotifier {
194+
195+
@Override
196+
public void sendAlarmMsg(NotifyPlatform notifyPlatform, NotifyItemEnum notifyItemEnum) {
197+
throw new IllegalStateException("alarm failed");
198+
}
199+
}
200+
}

0 commit comments

Comments
 (0)