├── .gitignore
├── .travis.yml
├── README.md
├── img
└── principle.jpg
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ ├── alibaba
│ │ └── dubbo
│ │ │ ├── common
│ │ │ └── Node.java
│ │ │ └── rpc
│ │ │ └── Invoker.java
│ │ └── cmt
│ │ └── des
│ │ ├── EasyMockClusterWrapper.java
│ │ ├── EasyMockHandler.java
│ │ ├── EasyMockInvoker.java
│ │ ├── MockConfig.java
│ │ ├── MockValueResolver.java
│ │ ├── PrimitiveWrapper.java
│ │ ├── compatible
│ │ ├── CompatibleEasyMockClusterWrapper.java
│ │ ├── CompatibleEasyMockHandler.java
│ │ ├── CompatibleEasyMockInvoker.java
│ │ └── CompatibleResultAdaptor.java
│ │ └── util
│ │ ├── ClassHelper.java
│ │ ├── ConfigUtils.java
│ │ ├── HttpUtil.java
│ │ └── ReflectUtils.java
└── resources
│ └── META-INF
│ └── dubbo
│ ├── com.alibaba.dubbo.rpc.cluster.Cluster
│ └── org.apache.dubbo.rpc.cluster.Cluster
└── test
├── java
└── tests
│ ├── HelloService.java
│ ├── application
│ └── EasyMockTest.groovy
│ ├── component
│ └── MockValueResolverTest.groovy
│ └── model
│ ├── BaseResponse.java
│ ├── Person.java
│ ├── QueryCurNeedRepayResponse.java
│ └── Result.java
└── resources
└── mock.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven ignore
2 | target/
3 | *.jar
4 | !.mvn/wrapper/*
5 | *.war
6 | *.zip
7 | *.tar
8 | *.tar.gz
9 |
10 | # eclipse ignore
11 | .settings/
12 | .project
13 | .classpath
14 |
15 | # idea ignore
16 | .idea/
17 | *.ipr
18 | *.iml
19 | *.iws
20 |
21 | # temp ignore
22 | *.log
23 | *.cache
24 | *.diff
25 | *.patch
26 | *.tmp
27 |
28 | # system ignore
29 | .DS_Store
30 | Thumbs.db
31 | *.orig
32 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | sudo: false # faster builds
3 |
4 | jdk:
5 | - openjdk8
6 |
7 | cache:
8 | directories:
9 | - $HOME/.m2
10 |
11 | install: skip
12 |
13 | script:
14 | - mvn --batch-mode clean install -DskipTests=false -Dmaven.javadoc.skip=true
15 |
16 | after_success:
17 | - bash <(curl -s https://codecov.io/bash)
18 | - echo "build success!"
19 |
20 | after_failure:
21 | - echo "build failed!
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/dsc-cmt/dubbo-easy-mock)
2 | ## 这个框架的作用
3 | 在自动测试中,针对dubbo接口进行mock的框架
4 |
5 | ## 原理
6 | 利用dubbo的扩展点自动包装,通过EasyMockClusterWrapper将原本的rpc请求改写为http请求转发到mock服务器返回我们对应mock结果
7 |
8 | 
9 |
10 | ## 使用
11 | ### 1. 添加依赖
12 | mvn clean package install (deploy) -Dmaven.test.skip=true 编译安装依赖到本地/远程仓库
13 |
14 | ```xml
15 |
16 | com.cmt
17 | dubbo-easy-mock
18 | 1.1.0
19 |
20 |
21 | org.apache.dubbo
22 | dubbo
23 |
24 |
25 |
26 | ```
27 | ### 2. classpath增加mock.properties
28 | ```
29 | ## 是否启用mock
30 | easymock.enable=true
31 | ## mock服务器地址
32 | easymock.server.url=https://easy-mock.com/mock/5c77afd53ecfbb573cba5df8/test
33 | ## 接口级别mock开关
34 | easymock.tests.HelloService=true
35 | ## 方法级别mock开关,优先级大于接口级别
36 | easymock.tests.HelloService.hello=true
37 | ```
38 |
39 | ### 3. mock服务-请求约束
40 |
41 | 本框架对mock服务器不做限制,但是发送的mock请求需要遵循以下约束
42 | 1. 请求类型为GET,请求path为/接口全限定名/方法名
43 | 2. 返回格式为json
44 | 对于基本类型,因为json仅支持对象和数组两种结构,所以需要用以下格式嵌套一层
45 | ```
46 | {
47 | "data":xxx
48 | }
49 | ```
50 | 对于其他类型,比如对象,Map,Collection等其他类型,与FastJson生成的一致即可
51 |
52 | mock服务器推荐 [easy-mock](https://github.com/easy-mock/easy-mock)或者[mockserver](https://github.com/mock-server/mockserver)这两个项目
53 |
54 | ## 更新
55 | 2020-03-12 - 兼容apache和alibaba版本的dubbo
56 |
57 | ## 示例工程
58 | [dubbo-easy-mock-demo](https://github.com/dsc-cmt/dubbo-easy-mock-demo)
59 |
60 | ## 相关文章
61 | [针对Dubbo接口Mock的解决方案](https://www.jianshu.com/p/d71c7771b9c9)
62 |
--------------------------------------------------------------------------------
/img/principle.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dsc-cmt/dubbo-easy-mock/a5e18febba25bfc1a054c6fade38d20ec4905d1a/img/principle.jpg
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | io.github.shengchaojie
8 | dubbo-easy-mock
9 | 1.1.0
10 |
11 |
12 | 1.8
13 | 2.6.8
14 | 4.3.2.RELEASE
15 | utf-8
16 | 1.8
17 | 1.8
18 |
19 |
20 |
21 |
22 | org.apache.dubbo
23 | dubbo
24 | 2.7.4.1
25 |
26 |
27 |
28 | org.projectlombok
29 | lombok
30 | 1.18.10
31 | provided
32 |
33 |
34 |
35 | org.apache.httpcomponents
36 | httpclient
37 | 4.5.10
38 |
39 |
40 |
41 | org.slf4j
42 | slf4j-api
43 | 1.7.29
44 |
45 |
46 |
47 | com.alibaba
48 | fastjson
49 | 1.2.62
50 |
51 |
52 |
53 | org.apache.curator
54 | curator-client
55 | 4.0.1
56 | test
57 |
58 |
59 |
60 | org.apache.curator
61 | curator-framework
62 | 2.7.0
63 | test
64 |
65 |
66 |
67 | org.apache.curator
68 | curator-recipes
69 | 2.7.0
70 | test
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | ch.qos.logback
82 | logback-classic
83 | 1.2.3
84 | test
85 |
86 |
87 |
88 | ch.qos.logback
89 | logback-core
90 | 1.2.3
91 | test
92 |
93 |
94 |
95 | org.spockframework
96 | spock-core
97 | 1.2-groovy-2.4
98 |
99 |
100 |
101 |
102 |
103 |
104 | org.spockframework
105 | spock-bom
106 | 2.0-M1-groovy-2.5
107 | pom
108 | import
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | org.codehaus.gmavenplus
117 | gmavenplus-plugin
118 | 1.6
119 |
120 |
121 |
122 | compile
123 | compileTests
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/common/Node.java:
--------------------------------------------------------------------------------
1 | package com.alibaba.dubbo.common;
2 |
3 | /**
4 | * @author shengchaojie
5 | * @date 2020-03-12
6 | **/
7 | public interface Node {
8 |
9 | /**
10 | * get url.
11 | *
12 | * @return url.
13 | */
14 | URL getUrl();
15 |
16 | /**
17 | * is available.
18 | *
19 | * @return available.
20 | */
21 | boolean isAvailable();
22 |
23 | /**
24 | * destroy.
25 | */
26 | void destroy();
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/alibaba/dubbo/rpc/Invoker.java:
--------------------------------------------------------------------------------
1 | package com.alibaba.dubbo.rpc;
2 |
3 | import com.alibaba.dubbo.common.Node;
4 |
5 | /**
6 | * @author shengchaojie
7 | * @date 2020-03-12
8 | **/
9 | public interface Invoker extends Node {
10 |
11 | /**
12 | * get service interface.
13 | *
14 | * @return service interface.
15 | */
16 | Class getInterface();
17 |
18 | /**
19 | * invoke.
20 | *
21 | * @param invocation
22 | * @return result
23 | * @throws RpcException
24 | */
25 | Result invoke(Invocation invocation) throws RpcException;
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/EasyMockClusterWrapper.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des;
2 |
3 | import org.apache.dubbo.rpc.Invoker;
4 | import org.apache.dubbo.rpc.RpcException;
5 | import org.apache.dubbo.rpc.cluster.Cluster;
6 | import org.apache.dubbo.rpc.cluster.Directory;
7 |
8 |
9 | /**
10 | * 采用SPI的包装类 包装Cluster扩展点
11 | * 如果开启easymock 直接走easymock的逻辑
12 | * @author shengchaojie
13 | * @date 2019-06-17
14 | **/
15 | public class EasyMockClusterWrapper implements Cluster {
16 |
17 | private Cluster cluster;
18 |
19 | public EasyMockClusterWrapper(Cluster cluster) {
20 | this.cluster = cluster;
21 | }
22 |
23 | @Override
24 | public Invoker join(Directory directory) throws RpcException {
25 | //防御性前置判断
26 | if(MockConfig.INSTANCE.isMockEnable()) {
27 | return new EasyMockInvoker<>(directory, this.cluster.join(directory));
28 | }
29 |
30 | return this.cluster.join(directory);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/EasyMockHandler.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des;
2 |
3 | import com.cmt.des.util.ClassHelper;
4 | import com.cmt.des.util.HttpUtil;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.apache.dubbo.rpc.AppResponse;
7 | import org.apache.dubbo.rpc.Invocation;
8 | import org.apache.dubbo.rpc.Invoker;
9 | import org.apache.dubbo.rpc.Result;
10 |
11 | import java.lang.reflect.Type;
12 |
13 | /**
14 | * @author shengchaojie
15 | * @date 2019-06-17
16 | **/
17 | @Slf4j
18 | public class EasyMockHandler {
19 |
20 |
21 | public static Result invoke(Invoker invoker, Invocation invocation, String interfaceName, String methodName) {
22 | //mock总开关
23 | if (!MockConfig.INSTANCE.isMockEnable()) {
24 | return invoker.invoke(invocation);
25 | }
26 |
27 | if (MockConfig.INSTANCE.isMethodMockEnable(interfaceName, methodName)||
28 | MockConfig.INSTANCE.isInterfaceMockEnable(interfaceName)) {
29 | String mockUrl = MockConfig.INSTANCE.buildMockRequestUrl(interfaceName, methodName);
30 | log.debug("mockUrl:{}", mockUrl);
31 | try {
32 | //通过easymock返回mock数据
33 | String mockValue = HttpUtil.doGet(mockUrl);
34 | //通过反射拿到返回的类型
35 | Type[] returnTypes = ClassHelper.getReturnType(interfaceName, methodName, invocation.getParameterTypes());
36 | return new AppResponse(MockValueResolver.resolve(mockValue, returnTypes[0], returnTypes.length > 1 ? returnTypes[1] : null));
37 | } catch (Exception e) {
38 | // TODO: 2020-02-08 同样的异常处理
39 | log.error("interface:{} method:{}mock失败,转为正常调用", interfaceName, methodName, e);
40 | }
41 | }
42 | //正常调用
43 | return invoker.invoke(invocation);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/EasyMockInvoker.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des;
2 |
3 |
4 | import org.apache.dubbo.common.URL;
5 | import org.apache.dubbo.rpc.Invocation;
6 | import org.apache.dubbo.rpc.Invoker;
7 | import org.apache.dubbo.rpc.Result;
8 | import org.apache.dubbo.rpc.RpcException;
9 | import org.apache.dubbo.rpc.cluster.Directory;
10 |
11 | /**
12 | * @author shengchaojie
13 | * @date 2019-06-17
14 | **/
15 | public class EasyMockInvoker implements Invoker {
16 |
17 | private final Directory directory;
18 |
19 | private final Invoker invoker;
20 |
21 | public EasyMockInvoker(Directory directory, Invoker invoker) {
22 | this.directory = directory;
23 | this.invoker = invoker;
24 | }
25 |
26 | @Override
27 | public Class getInterface() {
28 | return directory.getInterface();
29 | }
30 |
31 | @Override
32 | public Result invoke(Invocation invocation) throws RpcException {
33 | String interfaceName = invoker.getInterface().getCanonicalName();
34 | String methodName = invocation.getMethodName();
35 | return EasyMockHandler.invoke(invoker, invocation, interfaceName, methodName);
36 | }
37 |
38 | @Override
39 | public URL getUrl() {
40 | return directory.getUrl();
41 | }
42 |
43 | @Override
44 | public boolean isAvailable() {
45 | //这边返回true 让check=true的情况也通过
46 | return true;
47 | }
48 |
49 | @Override
50 | public void destroy() {
51 | this.invoker.destroy();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/MockConfig.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des;
2 |
3 | import com.cmt.des.util.ConfigUtils;
4 | import lombok.Getter;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 | import java.util.Optional;
10 | import java.util.Properties;
11 |
12 | /**
13 | * @author shengchaojie
14 | * @date 2020-02-07
15 | **/
16 | @Slf4j
17 | public class MockConfig {
18 |
19 | private static final String MOCK_FILE_NAME = "mock.properties";
20 |
21 | public static final MockConfig INSTANCE = new MockConfig();
22 |
23 | private static final String REQUEST_URL_FORMAT = "%s/%s/%s";
24 |
25 | private Boolean enable;
26 |
27 | @Getter
28 | private String mockServerUrl;
29 |
30 | private Map interfaceMockConfig = new HashMap<>();
31 |
32 | private MockConfig() {
33 | Properties mockProperties = ConfigUtils.loadProperties(MOCK_FILE_NAME);
34 | for(String key : mockProperties.stringPropertyNames()){
35 | String value = mockProperties.getProperty(key);
36 | if("easymock.enable".equals(key)){
37 | enable = "true".equals(value);
38 | }else if("easymock.server.url".equals(key)){
39 | mockServerUrl = value;
40 | }else if(key.startsWith("easymock.")){
41 | interfaceMockConfig.put(key.substring(9),"true".equals(value));
42 | }else{
43 | log.info("无效配置项:key={},value={}",key,value);
44 | }
45 | }
46 | }
47 |
48 | public Boolean isMockEnable(){
49 | return Optional.ofNullable(enable).orElse(false);
50 | }
51 |
52 | public Boolean isInterfaceMockEnable(String interfaceName){
53 | return Optional.ofNullable(interfaceMockConfig.get(interfaceName)).orElse(false);
54 | }
55 |
56 | public Boolean isMethodMockEnable(String interfaceName, String methodName){
57 | return Optional.ofNullable(interfaceMockConfig.get(interfaceName+"."+methodName)).orElse(false);
58 | }
59 |
60 | public String buildMockRequestUrl(String interfaceName, String methodName){
61 | return String.format(REQUEST_URL_FORMAT,mockServerUrl,interfaceName,methodName);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/MockValueResolver.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.cmt.des.util.ClassHelper;
5 |
6 | import java.lang.reflect.Type;
7 |
8 | /**
9 | * @author shengchaojie
10 | * @date 2020-02-09
11 | **/
12 | public class MockValueResolver {
13 |
14 | public static Object resolve(String mockValue, Type type,Type genericType) {
15 | if (Void.TYPE.isAssignableFrom((Class>) type)) {
16 | return null;
17 | }
18 |
19 | Object value = null;
20 | if (ClassHelper.isPrimitive((Class>) type)) {
21 | //处理内置类型
22 | //解决easymock不支持基本类型返回的问题
23 | PrimitiveWrapper primitiveWrapper = JSON.parseObject(mockValue, PrimitiveWrapper.class);
24 | value = JSON.parseObject(primitiveWrapper.getData().toString(),type);
25 | } else if (mockValue.startsWith("{") || mockValue.startsWith("[")) {
26 | //处理普通对象
27 | value = JSON.parseObject(mockValue, genericType!=null?genericType:type);
28 | } else {
29 | // TODO: 2020-02-08 走到这边代表出错了 考虑错误如何处理
30 | value = mockValue;
31 | }
32 |
33 | return value;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/PrimitiveWrapper.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.io.Serializable;
8 |
9 |
10 | /**
11 | * @author shengchaojie
12 | * @date 2019-03-04
13 | **/
14 | @Data
15 | @NoArgsConstructor
16 | @AllArgsConstructor
17 | public class PrimitiveWrapper implements Serializable {
18 |
19 | private Object data;
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/compatible/CompatibleEasyMockClusterWrapper.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.compatible;
2 |
3 | import com.alibaba.dubbo.rpc.Invoker;
4 | import com.alibaba.dubbo.rpc.RpcException;
5 | import com.alibaba.dubbo.rpc.cluster.Cluster;
6 | import com.alibaba.dubbo.rpc.cluster.Directory;
7 | import com.cmt.des.MockConfig;
8 |
9 |
10 | /**
11 | * 采用SPI的包装类 包装Cluster扩展点
12 | * 如果开启easymock 直接走easymock的逻辑
13 | * @author shengchaojie
14 | * @date 2019-06-17
15 | **/
16 | public class CompatibleEasyMockClusterWrapper implements Cluster {
17 |
18 | private Cluster cluster;
19 |
20 | public CompatibleEasyMockClusterWrapper(Cluster cluster) {
21 | this.cluster = cluster;
22 | }
23 |
24 | @Override
25 | public Invoker join(Directory directory) throws RpcException {
26 | //防御性前置判断
27 | if(MockConfig.INSTANCE.isMockEnable()) {
28 | return new CompatibleEasyMockInvoker<>(directory, this.cluster.join(directory));
29 | }
30 |
31 | return this.cluster.join(directory);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/compatible/CompatibleEasyMockHandler.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.compatible;
2 |
3 | import com.alibaba.dubbo.rpc.Invocation;
4 | import com.alibaba.dubbo.rpc.Invoker;
5 | import com.alibaba.dubbo.rpc.Result;
6 | import com.alibaba.fastjson.JSON;
7 | import com.cmt.des.MockConfig;
8 | import com.cmt.des.MockValueResolver;
9 | import com.cmt.des.util.ClassHelper;
10 | import com.cmt.des.util.HttpUtil;
11 | import lombok.extern.slf4j.Slf4j;
12 |
13 | import java.lang.reflect.Type;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 | /**
18 | * @author shengchaojie
19 | * @date 2019-06-17
20 | **/
21 | @Slf4j
22 | public class CompatibleEasyMockHandler {
23 |
24 | public static Result invoke(Invoker invoker, Invocation invocation, String interfaceName, String methodName) {
25 | //mock总开关
26 | if (!MockConfig.INSTANCE.isMockEnable()) {
27 | return invoker.invoke(invocation);
28 | }
29 |
30 | if (MockConfig.INSTANCE.isMethodMockEnable(interfaceName, methodName)||
31 | MockConfig.INSTANCE.isInterfaceMockEnable(interfaceName)) {
32 | String mockUrl = MockConfig.INSTANCE.buildMockRequestUrl(interfaceName, methodName);
33 | log.debug("mockUrl:{}", mockUrl);
34 | try {
35 | //通过easymock返回mock数据
36 | String mockValue = HttpUtil.doGet(mockUrl);
37 | //通过反射拿到返回的类型
38 | Type[] returnTypes = ClassHelper.getReturnType(interfaceName, methodName, invocation.getParameterTypes());
39 | final Object result = MockValueResolver.resolve(mockValue, returnTypes[0], returnTypes.length > 1 ? returnTypes[1] : null);
40 | log.info("mock 返回值:{}", JSON.toJSONString(result));
41 | return new CompatibleResultAdaptor() {
42 | @Override
43 | public Object getValue() {
44 | return result;
45 | }
46 |
47 | @Override
48 | public Object recreate() throws Throwable {
49 | return result;
50 | }
51 |
52 | @Override
53 | public Map getAttachments() {
54 | return new HashMap<>(0);
55 | }
56 |
57 | @Override
58 | public boolean hasException() {
59 | return false;
60 | }
61 | };
62 | } catch (Exception e) {
63 | // TODO: 2020-02-08 同样的异常处理
64 | log.error("interface:{} method:{}mock失败,转为正常调用", interfaceName, methodName, e);
65 | }
66 | }
67 | //正常调用
68 | return invoker.invoke(invocation);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/compatible/CompatibleEasyMockInvoker.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.compatible;
2 |
3 |
4 | import com.alibaba.dubbo.common.URL;
5 | import com.alibaba.dubbo.rpc.Invocation;
6 | import com.alibaba.dubbo.rpc.Invoker;
7 | import com.alibaba.dubbo.rpc.Result;
8 | import com.alibaba.dubbo.rpc.RpcException;
9 | import com.alibaba.dubbo.rpc.cluster.Directory;
10 | import lombok.extern.slf4j.Slf4j;
11 |
12 | /**
13 | * @author shengchaojie
14 | * @date 2019-06-17
15 | **/
16 | @Slf4j
17 | public class CompatibleEasyMockInvoker implements Invoker {
18 |
19 | private final Directory directory;
20 |
21 | private final Invoker invoker;
22 |
23 | public CompatibleEasyMockInvoker(Directory directory, Invoker invoker) {
24 | this.directory = directory;
25 | this.invoker = invoker;
26 | }
27 |
28 | @Override
29 | public Class getInterface() {
30 | return directory.getInterface();
31 | }
32 |
33 | @Override
34 | public Result invoke(Invocation invocation) throws RpcException {
35 | String interfaceName = invoker.getInterface().getCanonicalName();
36 | String methodName = invocation.getMethodName();
37 | return CompatibleEasyMockHandler.invoke(invoker, invocation, interfaceName, methodName);
38 | }
39 |
40 | @Override
41 | public URL getUrl() {
42 | return directory.getUrl();
43 | }
44 |
45 | @Override
46 | public boolean isAvailable() {
47 | //这边返回true 让check=true的情况也通过
48 | return true;
49 | }
50 |
51 | @Override
52 | public void destroy() {
53 | this.invoker.destroy();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/compatible/CompatibleResultAdaptor.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.compatible;
2 |
3 | import com.alibaba.dubbo.rpc.Result;
4 |
5 | import java.util.Map;
6 | import java.util.concurrent.*;
7 | import java.util.function.BiConsumer;
8 | import java.util.function.BiFunction;
9 | import java.util.function.Consumer;
10 | import java.util.function.Function;
11 |
12 | /**
13 | * 兼容 alibaba dubbo 和 apache dubbo的 Result
14 | * @author shengchaojie
15 | * @date 2020-03-10
16 | **/
17 | public abstract class CompatibleResultAdaptor implements Result {
18 | @Override
19 | public Object getValue() {
20 | return null;
21 | }
22 |
23 | @Override
24 | public Throwable getException() {
25 | return null;
26 | }
27 |
28 | @Override
29 | public boolean hasException() {
30 | return false;
31 | }
32 |
33 | @Override
34 | public Object recreate() throws Throwable {
35 | return null;
36 | }
37 |
38 | @Override
39 | public Map getAttachments() {
40 | return null;
41 | }
42 |
43 | @Override
44 | public void addAttachments(Map map) {
45 |
46 | }
47 |
48 | @Override
49 | public void setAttachments(Map map) {
50 |
51 | }
52 |
53 | @Override
54 | public String getAttachment(String key) {
55 | return null;
56 | }
57 |
58 | @Override
59 | public String getAttachment(String key, String defaultValue) {
60 | return null;
61 | }
62 |
63 | @Override
64 | public void setAttachment(String key, String value) {
65 |
66 | }
67 |
68 | @Override
69 | public org.apache.dubbo.rpc.Result getNow(org.apache.dubbo.rpc.Result valueIfAbsent) {
70 | return null;
71 | }
72 |
73 | @Override
74 | public org.apache.dubbo.rpc.Result whenCompleteWithContext(BiConsumer fn) {
75 | return null;
76 | }
77 |
78 | @Override
79 | public CompletionStage thenApply(Function super org.apache.dubbo.rpc.Result, ? extends U> fn) {
80 | return null;
81 | }
82 |
83 | @Override
84 | public CompletionStage thenApplyAsync(Function super org.apache.dubbo.rpc.Result, ? extends U> fn) {
85 | return null;
86 | }
87 |
88 | @Override
89 | public CompletionStage thenApplyAsync(Function super org.apache.dubbo.rpc.Result, ? extends U> fn, Executor executor) {
90 | return null;
91 | }
92 |
93 | @Override
94 | public CompletionStage thenAccept(Consumer super org.apache.dubbo.rpc.Result> action) {
95 | return null;
96 | }
97 |
98 | @Override
99 | public CompletionStage thenAcceptAsync(Consumer super org.apache.dubbo.rpc.Result> action) {
100 | return null;
101 | }
102 |
103 | @Override
104 | public CompletionStage thenAcceptAsync(Consumer super org.apache.dubbo.rpc.Result> action, Executor executor) {
105 | return null;
106 | }
107 |
108 | @Override
109 | public CompletionStage thenRun(Runnable action) {
110 | return null;
111 | }
112 |
113 | @Override
114 | public CompletionStage thenRunAsync(Runnable action) {
115 | return null;
116 | }
117 |
118 | @Override
119 | public CompletionStage thenRunAsync(Runnable action, Executor executor) {
120 | return null;
121 | }
122 |
123 | @Override
124 | public CompletionStage thenCombine(CompletionStage extends U> other, BiFunction super org.apache.dubbo.rpc.Result, ? super U, ? extends V> fn) {
125 | return null;
126 | }
127 |
128 | @Override
129 | public CompletionStage thenCombineAsync(CompletionStage extends U> other, BiFunction super org.apache.dubbo.rpc.Result, ? super U, ? extends V> fn) {
130 | return null;
131 | }
132 |
133 | @Override
134 | public CompletionStage thenCombineAsync(CompletionStage extends U> other, BiFunction super org.apache.dubbo.rpc.Result, ? super U, ? extends V> fn, Executor executor) {
135 | return null;
136 | }
137 |
138 | @Override
139 | public CompletionStage thenAcceptBoth(CompletionStage extends U> other, BiConsumer super org.apache.dubbo.rpc.Result, ? super U> action) {
140 | return null;
141 | }
142 |
143 | @Override
144 | public CompletionStage thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super org.apache.dubbo.rpc.Result, ? super U> action) {
145 | return null;
146 | }
147 |
148 | @Override
149 | public CompletionStage thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super org.apache.dubbo.rpc.Result, ? super U> action, Executor executor) {
150 | return null;
151 | }
152 |
153 | @Override
154 | public CompletionStage runAfterBoth(CompletionStage> other, Runnable action) {
155 | return null;
156 | }
157 |
158 | @Override
159 | public CompletionStage runAfterBothAsync(CompletionStage> other, Runnable action) {
160 | return null;
161 | }
162 |
163 | @Override
164 | public CompletionStage runAfterBothAsync(CompletionStage> other, Runnable action, Executor executor) {
165 | return null;
166 | }
167 |
168 | @Override
169 | public CompletionStage applyToEither(CompletionStage extends org.apache.dubbo.rpc.Result> other, Function super org.apache.dubbo.rpc.Result, U> fn) {
170 | return null;
171 | }
172 |
173 | @Override
174 | public CompletionStage applyToEitherAsync(CompletionStage extends org.apache.dubbo.rpc.Result> other, Function super org.apache.dubbo.rpc.Result, U> fn) {
175 | return null;
176 | }
177 |
178 | @Override
179 | public CompletionStage applyToEitherAsync(CompletionStage extends org.apache.dubbo.rpc.Result> other, Function super org.apache.dubbo.rpc.Result, U> fn, Executor executor) {
180 | return null;
181 | }
182 |
183 | @Override
184 | public CompletionStage acceptEither(CompletionStage extends org.apache.dubbo.rpc.Result> other, Consumer super org.apache.dubbo.rpc.Result> action) {
185 | return null;
186 | }
187 |
188 | @Override
189 | public CompletionStage acceptEitherAsync(CompletionStage extends org.apache.dubbo.rpc.Result> other, Consumer super org.apache.dubbo.rpc.Result> action) {
190 | return null;
191 | }
192 |
193 | @Override
194 | public CompletionStage acceptEitherAsync(CompletionStage extends org.apache.dubbo.rpc.Result> other, Consumer super org.apache.dubbo.rpc.Result> action, Executor executor) {
195 | return null;
196 | }
197 |
198 | @Override
199 | public CompletionStage runAfterEither(CompletionStage> other, Runnable action) {
200 | return null;
201 | }
202 |
203 | @Override
204 | public CompletionStage runAfterEitherAsync(CompletionStage> other, Runnable action) {
205 | return null;
206 | }
207 |
208 | @Override
209 | public CompletionStage runAfterEitherAsync(CompletionStage> other, Runnable action, Executor executor) {
210 | return null;
211 | }
212 |
213 | @Override
214 | public CompletionStage thenCompose(Function super org.apache.dubbo.rpc.Result, ? extends CompletionStage> fn) {
215 | return null;
216 | }
217 |
218 | @Override
219 | public CompletionStage thenComposeAsync(Function super org.apache.dubbo.rpc.Result, ? extends CompletionStage> fn) {
220 | return null;
221 | }
222 |
223 | @Override
224 | public CompletionStage thenComposeAsync(Function super org.apache.dubbo.rpc.Result, ? extends CompletionStage> fn, Executor executor) {
225 | return null;
226 | }
227 |
228 | @Override
229 | public CompletionStage exceptionally(Function fn) {
230 | return null;
231 | }
232 |
233 | @Override
234 | public CompletionStage whenComplete(BiConsumer super org.apache.dubbo.rpc.Result, ? super Throwable> action) {
235 | return null;
236 | }
237 |
238 | @Override
239 | public CompletionStage whenCompleteAsync(BiConsumer super org.apache.dubbo.rpc.Result, ? super Throwable> action) {
240 | return null;
241 | }
242 |
243 | @Override
244 | public CompletionStage whenCompleteAsync(BiConsumer super org.apache.dubbo.rpc.Result, ? super Throwable> action, Executor executor) {
245 | return null;
246 | }
247 |
248 | @Override
249 | public CompletionStage handle(BiFunction super org.apache.dubbo.rpc.Result, Throwable, ? extends U> fn) {
250 | return null;
251 | }
252 |
253 | @Override
254 | public CompletionStage handleAsync(BiFunction super org.apache.dubbo.rpc.Result, Throwable, ? extends U> fn) {
255 | return null;
256 | }
257 |
258 | @Override
259 | public CompletionStage handleAsync(BiFunction super org.apache.dubbo.rpc.Result, Throwable, ? extends U> fn, Executor executor) {
260 | return null;
261 | }
262 |
263 | @Override
264 | public CompletableFuture toCompletableFuture() {
265 | return null;
266 | }
267 |
268 | @Override
269 | public boolean cancel(boolean mayInterruptIfRunning) {
270 | return false;
271 | }
272 |
273 | @Override
274 | public boolean isCancelled() {
275 | return false;
276 | }
277 |
278 | @Override
279 | public boolean isDone() {
280 | return false;
281 | }
282 |
283 | @Override
284 | public org.apache.dubbo.rpc.Result get() throws InterruptedException, ExecutionException {
285 | return null;
286 | }
287 |
288 | @Override
289 | public org.apache.dubbo.rpc.Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
290 | return null;
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/util/ClassHelper.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.util;
2 |
3 |
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import java.lang.reflect.Method;
8 | import java.lang.reflect.Type;
9 |
10 | /**
11 | * @author shengchaojie
12 | * @date 2019-03-04
13 | **/
14 | public class ClassHelper {
15 |
16 | private static final Logger logger = LoggerFactory.getLogger(ClassHelper.class);
17 |
18 | public static boolean isPrimitive(Class> type) {
19 | return type.isPrimitive()
20 | || type == String.class
21 | || type == Character.class
22 | || type == Boolean.class
23 | || type == Byte.class
24 | || type == Short.class
25 | || type == Integer.class
26 | || type == Long.class
27 | || type == Float.class
28 | || type == Double.class
29 | || type == Object.class;
30 | }
31 |
32 | public static Type[] getReturnType(String interfaceName,String methodName,Class>[] parameterTypes){
33 | Class> cls = ReflectUtils.forName(interfaceName);
34 | Method method = null;
35 | try {
36 | method = cls.getMethod(methodName, parameterTypes);
37 | } catch (NoSuchMethodException e) {
38 | logger.error("反射获取返回类型失败",e);
39 | return null;
40 | }
41 | return new Type[]{method.getReturnType(), method.getGenericReturnType()};
42 | }
43 |
44 | public static ClassLoader getClassLoader(){
45 | return getClassLoader(ClassHelper.class);
46 | }
47 |
48 | public static ClassLoader getClassLoader(Class> clazz) {
49 | ClassLoader cl = null;
50 | try {
51 | cl = Thread.currentThread().getContextClassLoader();
52 | } catch (Throwable ex) {
53 | // Cannot access thread context ClassLoader - falling back to system class loader...
54 | }
55 | if (cl == null) {
56 | // No thread context class loader -> use class loader of this class.
57 | cl = clazz.getClassLoader();
58 | if (cl == null) {
59 | // getClassLoader() returning null indicates the bootstrap ClassLoader
60 | try {
61 | cl = ClassLoader.getSystemClassLoader();
62 | } catch (Throwable ex) {
63 | // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
64 | }
65 | }
66 | }
67 |
68 | return cl;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/util/ConfigUtils.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.InputStream;
9 | import java.net.URL;
10 | import java.util.*;
11 | import java.util.regex.Pattern;
12 |
13 | /**
14 | * @author shengchaojie
15 | * @date 2020-03-12
16 | **/
17 | public class ConfigUtils {
18 |
19 | private static final Logger logger = LoggerFactory.getLogger(ConfigUtils.class);
20 |
21 | private static Pattern VARIABLE_PATTERN = Pattern.compile(
22 | "\\$\\s*\\{?\\s*([\\._0-9a-zA-Z]+)\\s*\\}?");
23 |
24 | private ConfigUtils() {
25 | }
26 |
27 |
28 | public static Properties loadProperties(String fileName) {
29 | return loadProperties(fileName, false, false);
30 | }
31 |
32 | /**
33 | * Load properties file to {@link Properties} from class path.
34 | *
35 | * @param fileName properties file name. for example: dubbo.properties
, METE-INF/conf/foo.properties
36 | * @param allowMultiFile if false
, throw {@link IllegalStateException} when found multi file on the class path.
37 | * @param optional is optional. if false
, log warn when properties config file not found!s
38 | * @return loaded {@link Properties} content.
39 | * - return empty Properties if no file found.
40 | *
- merge multi properties file if found multi file
41 | *
42 | * @throws IllegalStateException not allow multi-file, but multi-file exist on class path.
43 | */
44 | public static Properties loadProperties(String fileName, boolean allowMultiFile, boolean optional) {
45 | Properties properties = new Properties();
46 | // add scene judgement in windows environment Fix 2557
47 | if (checkFileNameExist(fileName)) {
48 | try {
49 | FileInputStream input = new FileInputStream(fileName);
50 | try {
51 | properties.load(input);
52 | } finally {
53 | input.close();
54 | }
55 | } catch (Throwable e) {
56 | logger.warn("Failed to load " + fileName + " file from " + fileName + "(ignore this file): " + e.getMessage(), e);
57 | }
58 | return properties;
59 | }
60 |
61 | List list = new ArrayList();
62 | try {
63 | Enumeration urls = ClassHelper.getClassLoader(ConfigUtils.class).getResources(fileName);
64 | list = new ArrayList();
65 | while (urls.hasMoreElements()) {
66 | list.add(urls.nextElement());
67 | }
68 | } catch (Throwable t) {
69 | logger.warn("Fail to load " + fileName + " file: " + t.getMessage(), t);
70 | }
71 |
72 | if (list.isEmpty()) {
73 | if (!optional) {
74 | logger.warn("No " + fileName + " found on the class path.");
75 | }
76 | return properties;
77 | }
78 |
79 | if (!allowMultiFile) {
80 | if (list.size() > 1) {
81 | String errMsg = String.format("only 1 %s file is expected, but %d dubbo.properties files found on class path: %s",
82 | fileName, list.size(), list.toString());
83 | logger.warn(errMsg);
84 | }
85 |
86 | // fall back to use method getResourceAsStream
87 | try {
88 | properties.load(ClassHelper.getClassLoader(ConfigUtils.class).getResourceAsStream(fileName));
89 | } catch (Throwable e) {
90 | logger.warn("Failed to load " + fileName + " file from " + fileName + "(ignore this file): " + e.getMessage(), e);
91 | }
92 | return properties;
93 | }
94 |
95 | logger.info("load " + fileName + " properties file from " + list);
96 |
97 | for (java.net.URL url : list) {
98 | try {
99 | Properties p = new Properties();
100 | InputStream input = url.openStream();
101 | if (input != null) {
102 | try {
103 | p.load(input);
104 | properties.putAll(p);
105 | } finally {
106 | try {
107 | input.close();
108 | } catch (Throwable t) {
109 | }
110 | }
111 | }
112 | } catch (Throwable e) {
113 | logger.warn("Fail to load " + fileName + " file from " + url + "(ignore this file): " + e.getMessage(), e);
114 | }
115 | }
116 |
117 | return properties;
118 | }
119 |
120 | /**
121 | * check if the fileName can be found in filesystem
122 | *
123 | * @param fileName
124 | * @return
125 | */
126 | private static boolean checkFileNameExist(String fileName) {
127 | File file = new File(fileName);
128 | return file.exists();
129 | }
130 |
131 |
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/util/HttpUtil.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.util;
2 |
3 | import org.apache.http.client.methods.CloseableHttpResponse;
4 | import org.apache.http.client.methods.HttpGet;
5 | import org.apache.http.impl.client.CloseableHttpClient;
6 | import org.apache.http.impl.client.HttpClients;
7 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
8 | import org.apache.http.util.EntityUtils;
9 |
10 | import java.io.IOException;
11 |
12 | /**
13 | * @author shengchaojie
14 | * @date 2019-03-04
15 | **/
16 | public class HttpUtil {
17 |
18 | private static CloseableHttpClient closeableHttpClient;
19 |
20 | private final static Object syncLock = new Object();
21 |
22 | private static CloseableHttpClient getHttpClient(){
23 | if(closeableHttpClient==null){
24 | synchronized (syncLock){
25 | if(closeableHttpClient==null){
26 | closeableHttpClient = createHttpClient();
27 | }
28 | }
29 | }
30 | return closeableHttpClient;
31 | }
32 |
33 | private static CloseableHttpClient createHttpClient(){
34 | //连接池默认设置不改了
35 | PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
36 |
37 | return HttpClients.custom()
38 | .setConnectionManager(poolingHttpClientConnectionManager)
39 | .build();
40 | }
41 |
42 | public static String doGet(String url) throws IOException{
43 | HttpGet httpGet = new HttpGet(url);
44 | CloseableHttpResponse httpResponse =getHttpClient().execute(httpGet);
45 |
46 | return EntityUtils.toString(httpResponse.getEntity(),"utf-8");
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/cmt/des/util/ReflectUtils.java:
--------------------------------------------------------------------------------
1 | package com.cmt.des.util;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 | import java.util.concurrent.ConcurrentMap;
5 |
6 | /**
7 | * ReflectUtils
8 | */
9 | public final class ReflectUtils {
10 |
11 | /**
12 | * void(V).
13 | */
14 | public static final char JVM_VOID = 'V';
15 |
16 | /**
17 | * boolean(Z).
18 | */
19 | public static final char JVM_BOOLEAN = 'Z';
20 |
21 | /**
22 | * byte(B).
23 | */
24 | public static final char JVM_BYTE = 'B';
25 |
26 | /**
27 | * char(C).
28 | */
29 | public static final char JVM_CHAR = 'C';
30 |
31 | /**
32 | * double(D).
33 | */
34 | public static final char JVM_DOUBLE = 'D';
35 |
36 | /**
37 | * float(F).
38 | */
39 | public static final char JVM_FLOAT = 'F';
40 |
41 | /**
42 | * int(I).
43 | */
44 | public static final char JVM_INT = 'I';
45 |
46 | /**
47 | * long(J).
48 | */
49 | public static final char JVM_LONG = 'J';
50 |
51 | /**
52 | * short(S).
53 | */
54 | public static final char JVM_SHORT = 'S';
55 |
56 |
57 | private static final ConcurrentMap> NAME_CLASS_CACHE = new ConcurrentHashMap>();
58 |
59 |
60 | private ReflectUtils() {
61 | }
62 |
63 |
64 | public static Class> forName(String name) {
65 | try {
66 | return name2class(name);
67 | } catch (ClassNotFoundException e) {
68 | throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
69 | }
70 | }
71 |
72 |
73 | /**
74 | * name to class.
75 | * "boolean" => boolean.class
76 | * "java.util.Map[][]" => java.util.Map[][].class
77 | *
78 | * @param name name.
79 | * @return Class instance.
80 | */
81 | public static Class> name2class(String name) throws ClassNotFoundException {
82 | return name2class(ClassHelper.getClassLoader(), name);
83 | }
84 |
85 | /**
86 | * name to class.
87 | * "boolean" => boolean.class
88 | * "java.util.Map[][]" => java.util.Map[][].class
89 | *
90 | * @param cl ClassLoader instance.
91 | * @param name name.
92 | * @return Class instance.
93 | */
94 | private static Class> name2class(ClassLoader cl, String name) throws ClassNotFoundException {
95 | int c = 0, index = name.indexOf('[');
96 | if (index > 0) {
97 | c = (name.length() - index) / 2;
98 | name = name.substring(0, index);
99 | }
100 | if (c > 0) {
101 | StringBuilder sb = new StringBuilder();
102 | while (c-- > 0) {
103 | sb.append("[");
104 | }
105 |
106 | if ("void".equals(name)) {
107 | sb.append(JVM_VOID);
108 | } else if ("boolean".equals(name)) {
109 | sb.append(JVM_BOOLEAN);
110 | } else if ("byte".equals(name)) {
111 | sb.append(JVM_BYTE);
112 | } else if ("char".equals(name)) {
113 | sb.append(JVM_CHAR);
114 | } else if ("double".equals(name)) {
115 | sb.append(JVM_DOUBLE);
116 | } else if ("float".equals(name)) {
117 | sb.append(JVM_FLOAT);
118 | } else if ("int".equals(name)) {
119 | sb.append(JVM_INT);
120 | } else if ("long".equals(name)) {
121 | sb.append(JVM_LONG);
122 | } else if ("short".equals(name)) {
123 | sb.append(JVM_SHORT);
124 | } else {
125 | // "java.lang.Object" ==> "Ljava.lang.Object;"
126 | sb.append('L').append(name).append(';');
127 | }
128 | name = sb.toString();
129 | } else {
130 | if ("void".equals(name)) {
131 | return void.class;
132 | }
133 | if ("boolean".equals(name)) {
134 | return boolean.class;
135 | }
136 | if ("byte".equals(name)) {
137 | return byte.class;
138 | }
139 | if ("char".equals(name)) {
140 | return char.class;
141 | }
142 | if ("double".equals(name)) {
143 | return double.class;
144 | }
145 | if ("float".equals(name)) {
146 | return float.class;
147 | }
148 | if ("int".equals(name)) {
149 | return int.class;
150 | }
151 | if ("long".equals(name)) {
152 | return long.class;
153 | }
154 | if ("short".equals(name)) {
155 | return short.class;
156 | }
157 | }
158 |
159 | if (cl == null) {
160 | cl = ClassHelper.getClassLoader();
161 | }
162 | Class> clazz = NAME_CLASS_CACHE.get(name);
163 | if (clazz == null) {
164 | clazz = Class.forName(name, true, cl);
165 | NAME_CLASS_CACHE.put(name, clazz);
166 | }
167 | return clazz;
168 | }
169 |
170 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.Cluster:
--------------------------------------------------------------------------------
1 | easymock=com.cmt.des.compatible.CompatibleEasyMockClusterWrapper
--------------------------------------------------------------------------------
/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster:
--------------------------------------------------------------------------------
1 | easymock=com.cmt.des.EasyMockClusterWrapper
--------------------------------------------------------------------------------
/src/test/java/tests/HelloService.java:
--------------------------------------------------------------------------------
1 | package tests;
2 |
3 | import tests.model.Person;
4 | import tests.model.Result;
5 |
6 | import java.util.Map;
7 |
8 | /**
9 | * @author shengchaojie
10 | * @date 2019-06-17
11 | **/
12 | public interface HelloService {
13 |
14 | String helloWorld();
15 |
16 | Long testLong1();
17 |
18 | long testLong2();
19 |
20 | void empty();
21 |
22 | Result genericMethod();
23 |
24 | Result genericMethod2();
25 |
26 | Person complexObjcet();
27 |
28 | Map returnMapMethod();
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/tests/application/EasyMockTest.groovy:
--------------------------------------------------------------------------------
1 | package tests.application
2 |
3 |
4 | import org.apache.dubbo.config.ApplicationConfig
5 | import org.apache.dubbo.config.ReferenceConfig
6 | import org.apache.dubbo.config.RegistryConfig
7 | import spock.lang.*
8 | import tests.HelloService
9 |
10 | /**
11 | * @author shengchaojie
12 | * @date 2019-06-17
13 | **/
14 | class EasyMockTest extends Specification {
15 |
16 | private static HelloService helloService;
17 |
18 | def setupSpec(){
19 | ApplicationConfig applicationConfig = new ApplicationConfig();
20 | applicationConfig.setName("test-consumer");
21 |
22 | RegistryConfig registryConfig = new RegistryConfig();
23 | registryConfig.setAddress("zookeeper://127.0.0.1:2181");
24 |
25 | ReferenceConfig referenceConfig = new ReferenceConfig();
26 | referenceConfig.setInterface(HelloService.class);
27 | referenceConfig.setRegistry(registryConfig);
28 | referenceConfig.setApplication(applicationConfig);
29 | referenceConfig.setCheck(false);
30 | helloService = referenceConfig.get();
31 | }
32 |
33 | def "test long"() {
34 | when :
35 | println helloService.testLong1()
36 | then:
37 | noExceptionThrown()
38 | when:
39 | helloService.testLong2()
40 | then:
41 | noExceptionThrown()
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/tests/component/MockValueResolverTest.groovy:
--------------------------------------------------------------------------------
1 | package tests.component
2 |
3 | import com.alibaba.fastjson.JSON
4 | import com.alibaba.fastjson.TypeReference
5 | import com.cmt.des.MockValueResolver
6 | import com.cmt.des.PrimitiveWrapper
7 | import spock.lang.Specification
8 | import tests.model.QueryCurNeedRepayResponse
9 | import tests.model.Result
10 |
11 | /**
12 | * @author shengchaojie* @date 2020-02-09
13 | * */
14 | class MockValueResolverTest extends Specification {
15 |
16 | def "test parse primitive"() {
17 | when:
18 | def value = MockValueResolver.resolve(JSON.toJSONString(new PrimitiveWrapper(originValue)), type, genericType)
19 | then:
20 | Objects.equals(value, originValue)
21 | where:
22 | originValue | type | genericType
23 | 1 | Integer | null
24 | }
25 |
26 | def "test parse not primitive"() {
27 | when:
28 | def value = MockValueResolver.resolve(JSON.toJSONString(originValue), type, genericType)
29 | then:
30 | Objects.equals(value, originValue)
31 | where:
32 | originValue | type | genericType
33 | new Result(123) | Result | new TypeReference>() {}.type
34 | new Result>(new Result(123)) | Result | new TypeReference>>() {
35 | }.type
36 | }
37 |
38 | def "test Object"(){
39 | given:
40 | String s = "{\n" +
41 | " \"code\": \"10000\",\n" +
42 | " \"interest\": 1,\n" +
43 | " \"msg\": \"成功\",\n" +
44 | " \"principal\": 0,\n" +
45 | " \"success\": true,\n" +
46 | " \"totalAmount\": 0\n" +
47 | "}";
48 | when:
49 | def value = MockValueResolver.resolve(s, QueryCurNeedRepayResponse.class, null)
50 | then:
51 | Objects.equals(value, originValue)
52 | }
53 |
54 |
55 | }
--------------------------------------------------------------------------------
/src/test/java/tests/model/BaseResponse.java:
--------------------------------------------------------------------------------
1 | package tests.model;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author shengchaojie
7 | * @date 2020-03-12
8 | **/
9 | @Data
10 | public class BaseResponse {
11 |
12 | private Boolean success;
13 | private String code;
14 | private String msg;
15 | private String subCode;
16 | private String subMsg;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/java/tests/model/Person.java:
--------------------------------------------------------------------------------
1 | package tests.model;
2 |
3 | import lombok.Data;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * @author shengchaojie
9 | * @date 2020-02-07
10 | **/
11 | @Data
12 | public class Person implements Serializable {
13 |
14 | private String s;
15 |
16 | private Long l;
17 |
18 | private long l1;
19 |
20 | private Integer i;
21 |
22 | private int i1;
23 |
24 | private Double d;
25 |
26 | private double d1;
27 |
28 | private Float f;
29 |
30 | private float f1;
31 |
32 | private Boolean b;
33 |
34 | private boolean b1;
35 |
36 | private Character c;
37 |
38 | private char c1;
39 |
40 | private Byte by;
41 |
42 | private byte by1;
43 |
44 |
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/tests/model/QueryCurNeedRepayResponse.java:
--------------------------------------------------------------------------------
1 | package tests.model;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author shengchaojie
7 | * @date 2020-03-12
8 | **/
9 | @Data
10 | public class QueryCurNeedRepayResponse extends BaseResponse{
11 |
12 | private Long totalAmount;
13 | private Long principal;
14 | private Long interest;
15 | private Long ovdAmount;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/tests/model/Result.java:
--------------------------------------------------------------------------------
1 | package tests.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | /**
7 | * @author shengchaojie
8 | * @date 2020-02-07
9 | **/
10 | @Data
11 | @AllArgsConstructor
12 | public class Result {
13 |
14 | private T data;
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/resources/mock.properties:
--------------------------------------------------------------------------------
1 | ## 是否启用mock
2 | easymock.enable=true
3 | ## easymock baseurl
4 | easymock.server.url=https://easy-mock.com/mock/5c77afd53ecfbb573cba5df8/fsc
5 | easymock.tests.HelloService=true
--------------------------------------------------------------------------------