diff --git a/cola-archetypes/cola-archetype-light/pom.xml b/cola-archetypes/cola-archetype-light/pom.xml
new file mode 100644
index 000000000..87aadac0f
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/pom.xml
@@ -0,0 +1,30 @@
+
+
+ 4.0.0
+
+ com.alibaba.cola
+ cola-archetype-light
+ 1.0.0-SNAPSHOT
+ maven-archetype
+
+ cola-archetype-light
+
+
+
+
+ org.apache.maven.archetype
+ archetype-packaging
+ 3.2.1
+
+
+
+
+
+
+ maven-archetype-plugin
+ 3.2.1
+
+
+
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/META-INF/maven/archetype-metadata.xml b/cola-archetypes/cola-archetype-light/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644
index 000000000..c8d4dcf54
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -0,0 +1,73 @@
+
+
+
+
+ src/main/java
+
+ **/*.java
+
+
+
+ src/main/resources
+
+ **/*.xml
+
+
+
+ src/main/resources
+
+ **/*.yml
+
+
+
+ src/test/java
+
+ **/*.java
+
+
+
+ src/test/resources
+
+ **/*.xml
+
+
+
+ src/test
+
+ **/*.http
+
+
+
+ src/test/resources
+
+ **/*.json
+ **/*.yml
+
+
+
+ .idea
+
+ **/*.xml
+
+
+
+ .idea
+
+ **/*.gitignore
+
+
+
+
+
+ img_1.png
+ charge-parent.iml
+ charge.iml
+ img.png
+ charging-system.iml
+ README.md
+
+
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/README.md b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/README.md
new file mode 100644
index 000000000..67db948d3
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/README.md
@@ -0,0 +1,39 @@
+# 运营商计费系统
+计费系统是一个典型的复杂问题场景,比较适合采用COLA架构,且发挥Domain层的价值。故将其作为COLA的另一个Sample。
+
+运营商计费系统的需求如下:
+
+运营商向用户提供电话服务,支持用户拨打/接听电话,并对通话收取费用。
+如:主动拨打电话收取 0.5 元/分钟的通话费用;接听电话收取 0.4 元/分钟的通话费用。
+
+运营商为了吸引客户,定义了若干电话套餐,总共有三种类型的套餐。我们要设计一个**计费系统**用于套餐计费规则的执行,保存计费记录,并通知**账户系统**扣减费用。
+
+_注意:在一次通话过程中,通话控制系统可能会调用多次计费系统进行计费。_
+
+- 基础套餐
+ 1. 主叫收费 0.5 元/分钟
+ 2. 被叫收费 0.4 元/分钟
+
+
+- 固定时长套餐
+ 1. 套餐月固定费 100 元,包含:200 分钟主叫通话时间+200 分钟被叫接听时间
+ 2. 套餐外部分不再参与打折优惠,主叫 0.5 元/分钟,被叫 0.4 元/分钟
+
+
+- 家庭套餐
+ 1. 套餐月固定费 20 元
+ 2. 用户可以指定 N 个号码作为自己的亲情号
+ 3. 用户接听/拨打亲情号均不收费
+ 4. 与亲情号之外的号码通话,主叫 0.5 元/分钟,被叫 0.4 元/分钟
+
+# 系统设计
+## 统一语言
+我经常说,建模就是在分析语言,对于任何问题域,熟悉领域知识、理清概念、统一语言都是非常必要且重要的事情。
+对于这个系统也不例外。
+![img_1.png](img_1.png)
+
+## 计费系统和周边系统的关系
+![img.png](img.png)
+
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/img.png b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/img.png
new file mode 100644
index 000000000..d8576ef73
Binary files /dev/null and b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/img.png differ
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/img_1.png b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/img_1.png
new file mode 100644
index 000000000..227f0f3ea
Binary files /dev/null and b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/img_1.png differ
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/pom.xml b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/pom.xml
new file mode 100644
index 000000000..8c3f03feb
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/pom.xml
@@ -0,0 +1,81 @@
+
+
+ 4.0.0
+
+ ${groupId}
+ ${artifactId}
+ ${version}
+
+
+ 17
+ 17
+ 17
+ UTF-8
+
+ 3.0.0
+ 1.3.0
+ 3.2.0
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.projectlombok
+ lombok
+ 1.18.22
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ mysql
+ mysql-connector-java
+ 8.0.33
+
+
+
+ com.alibaba.cola
+ cola-component-test-container
+ 4.4.0-SNAPSHOT
+
+
+
+ com.h2database
+ h2
+ test
+
+
+
+ org.wiremock
+ wiremock-standalone
+ 3.5.4
+ test
+
+
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/Application.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/Application.java
new file mode 100644
index 000000000..f06a30ded
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/Application.java
@@ -0,0 +1,15 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package};
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/adapter/ChargeController.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/adapter/ChargeController.java
new file mode 100644
index 000000000..82460af1e
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/adapter/ChargeController.java
@@ -0,0 +1,49 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.adapter;
+
+import ${package}.application.ChargeServiceI;
+import ${package}.application.dto.*;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+
+@RestController
+@Slf4j
+public class ChargeController {
+
+ @Resource
+ private ChargeServiceI chargeService;
+
+ @PostMapping("session/{sessionId}/begin")
+ public Response begin(@PathVariable(name = "sessionId") String sessionId,
+ @RequestParam("callingPhoneNo") String callingPhoneNo,
+ @RequestParam("calledPhoneNo") String calledPhoneNo) {
+ log.debug(sessionId + " " + callingPhoneNo + " " + calledPhoneNo);
+ BeginSessionRequest request = new BeginSessionRequest(sessionId, Long.valueOf(callingPhoneNo), Long.valueOf(calledPhoneNo));
+ return chargeService.begin(request);
+ }
+
+ @PostMapping("session/{sessionId}/charge")
+ public Response charge(@PathVariable(name = "sessionId") String sessionId,
+ @RequestParam int duration) {
+ log.debug(sessionId + " " + duration);
+ ChargeRequest request = new ChargeRequest(sessionId, duration);
+ return chargeService.charge(request);
+ }
+
+ @PostMapping("session/{sessionId}/end")
+ public Response end(@PathVariable(name = "sessionId") String sessionId,
+ @RequestParam int duration) {
+ log.debug(sessionId + " " + duration);
+ EndSessionRequest request = new EndSessionRequest(sessionId, duration);
+ return chargeService.end(request);
+ }
+
+ @GetMapping("{sessionId}/chargeRecords")
+ public MultiResponse getChargeRecord(@PathVariable(name = "sessionId") String sessionId) {
+ return chargeService.listChargeRecords(sessionId);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/ChargeServiceI.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/ChargeServiceI.java
new file mode 100644
index 000000000..daa6013d3
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/ChargeServiceI.java
@@ -0,0 +1,16 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application;
+
+import ${package}.application.dto.*;
+
+public interface ChargeServiceI {
+ Response begin(BeginSessionRequest request);
+
+ Response charge(ChargeRequest request);
+
+ Response end(EndSessionRequest request);
+
+ MultiResponse listChargeRecords(String sessionId);
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/ChargeServiceImpl.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/ChargeServiceImpl.java
new file mode 100644
index 000000000..c8e66f87f
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/ChargeServiceImpl.java
@@ -0,0 +1,93 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application;
+
+import ${package}.application.dto.*;
+import ${package}.domain.account.Account;
+import ${package}.domain.account.AccountDomainService;
+import ${package}.domain.charge.CallType;
+import ${package}.domain.charge.ChargeContext;
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.Session;
+import ${package}.domain.gateway.AccountGateway;
+import ${package}.domain.gateway.ChargeGateway;
+import ${package}.domain.gateway.SessionGateway;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@Slf4j
+public class ChargeServiceImpl implements ChargeServiceI {
+
+ @Resource
+ private SessionGateway sessionGateway;
+
+ @Resource
+ private AccountGateway accountGateway;
+
+ @Resource
+ private AccountDomainService accountDomainService;
+
+ @Resource
+ private ChargeGateway chargeGateway;
+
+ @Override
+ public Response begin(BeginSessionRequest request) {
+ Session session = request.toSession();
+ accountDomainService.canSessionStart(session);
+ sessionGateway.create(session);
+ log.debug("Session created successfully :" + session);
+ return Response.buildSuccess();
+ }
+
+ @Override
+ public Response charge(ChargeRequest request) {
+ log.debug("Do charge : " + request);
+ Session session = sessionGateway.get(request.getSessionId());
+ int durationToCharge = request.getDuration() - session.getChargedDuration();
+ List chargeRecordList = new ArrayList<>();
+ chargeCalling(session, durationToCharge, chargeRecordList);
+ chargeCalled(session, durationToCharge, chargeRecordList);
+ chargeGateway.saveAll(chargeRecordList);
+ session.setChargedDuration(request.getDuration());
+ return Response.buildSuccess();
+ }
+
+ private void chargeCalling(Session session, int durationToCharge, List chargeRecordList) {
+ Account callingAccount = accountGateway.getAccount(session.getCallingPhoneNo());
+ ChargeContext callingCtx = new ChargeContext(CallType.CALLING, session.getCallingPhoneNo(), session.getCalledPhoneNo(), durationToCharge);
+ callingCtx.session = session;
+ callingCtx.account = callingAccount;
+ chargeRecordList.addAll(callingAccount.charge(callingCtx));
+ }
+
+ private void chargeCalled(Session session, int durationToCharge, List chargeRecordList) {
+ Account calledAccount = accountGateway.getAccount(session.getCalledPhoneNo());
+ ChargeContext calledCtx = new ChargeContext(CallType.CALLED, session.getCalledPhoneNo(), session.getCallingPhoneNo(), durationToCharge);
+ calledCtx.session = session;
+ calledCtx.account = calledAccount;
+ chargeRecordList.addAll(calledAccount.charge(calledCtx));
+ }
+
+ @Override
+ public Response end(EndSessionRequest request) {
+ charge(request.toChargeRequest());
+ sessionGateway.end(request.getSessionId());
+ return Response.buildSuccess();
+ }
+
+ @Override
+ public MultiResponse listChargeRecords(String sessionId) {
+ List chargeRecordList = chargeGateway.findBySessionId(sessionId);
+ List chargeRecordDtoList = new ArrayList<>();
+ for (ChargeRecord chargeRecord : chargeRecordList) {
+ chargeRecordDtoList.add(ChargeRecordDto.fromEntity(chargeRecord));
+ }
+ return MultiResponse.of(chargeRecordDtoList);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/BeginSessionRequest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/BeginSessionRequest.java
new file mode 100644
index 000000000..0e9a7a6e2
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/BeginSessionRequest.java
@@ -0,0 +1,39 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application.dto;
+
+import ${package}.domain.charge.Session;
+import lombok.Data;
+
+@Data
+public class BeginSessionRequest {
+
+ /**
+ * 本次通话的UUID
+ */
+ private String sessionId;
+
+ /**
+ * 主叫电话号码
+ */
+ private long callingPhoneNo;
+
+ /**
+ * 被叫电话号码
+ */
+ private long calledPhoneNo;
+
+ public Session toSession(){
+ return new Session(sessionId, callingPhoneNo, calledPhoneNo);
+ }
+
+ public BeginSessionRequest() {
+ }
+
+ public BeginSessionRequest(String sessionId, long callingPhoneNo, long calledPhoneNo) {
+ this.sessionId = sessionId;
+ this.callingPhoneNo = callingPhoneNo;
+ this.calledPhoneNo = calledPhoneNo;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/ChargeRecordDto.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/ChargeRecordDto.java
new file mode 100644
index 000000000..d385ce6ed
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/ChargeRecordDto.java
@@ -0,0 +1,30 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application.dto;
+
+import ${package}.domain.charge.CallType;
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+
+public class ChargeRecordDto {
+ public Long id;
+ public String sessionId;
+ public long phoneNo;
+ public int chargeDuration;
+ public long cost;
+ public CallType callType;
+ public ChargePlanType chargePlanType;
+
+ public static ChargeRecordDto fromEntity(ChargeRecord chargeRecord){
+ ChargeRecordDto dto = new ChargeRecordDto();
+ dto.id = chargeRecord.getId();
+ dto.sessionId = chargeRecord.getSessionId();
+ dto.phoneNo = chargeRecord.getPhoneNo();
+ dto.chargeDuration = chargeRecord.getChargeDuration();
+ dto.cost = chargeRecord.getCost().getAmount();
+ dto.callType = chargeRecord.getCallType();
+ dto.chargePlanType = chargeRecord.getChargePlanType();
+ return dto;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/ChargeRequest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/ChargeRequest.java
new file mode 100644
index 000000000..3199a75a3
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/ChargeRequest.java
@@ -0,0 +1,25 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application.dto;
+
+import lombok.Data;
+
+@Data
+public class ChargeRequest {
+
+ private String sessionId;
+
+ /**
+ * 当前通话,截止目前的累计时间
+ */
+ private int duration;
+
+ public ChargeRequest() {
+ }
+
+ public ChargeRequest(String sessionId, int duration) {
+ this.sessionId = sessionId;
+ this.duration = duration;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/EndSessionRequest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/EndSessionRequest.java
new file mode 100644
index 000000000..4a5e161cb
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/EndSessionRequest.java
@@ -0,0 +1,31 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application.dto;
+
+import lombok.Data;
+
+@Data
+public class EndSessionRequest {
+ private String sessionId;
+
+ /**
+ * 当前通话,截止目前的累计时间
+ */
+ private int duration;
+
+ public ChargeRequest toChargeRequest() {
+ ChargeRequest chargeRequest = new ChargeRequest();
+ chargeRequest.setSessionId(sessionId);
+ chargeRequest.setDuration(duration);
+ return chargeRequest;
+ }
+
+ public EndSessionRequest() {
+ }
+
+ public EndSessionRequest(String sessionId, int duration) {
+ this.sessionId = sessionId;
+ this.duration = duration;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/MultiResponse.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/MultiResponse.java
new file mode 100644
index 000000000..ca8b2e19b
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/MultiResponse.java
@@ -0,0 +1,60 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application.dto;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class MultiResponse extends Response {
+
+ private static final long serialVersionUID = 1L;
+
+ private Collection data;
+
+ public List getData() {
+ if (null == data) {
+ return Collections.emptyList();
+ }
+ if (data instanceof List) {
+ return (List) data;
+ }
+ return new ArrayList<>(data);
+ }
+
+ public void setData(Collection data) {
+ this.data = data;
+ }
+
+ public boolean isEmpty() {
+ return data == null || data.isEmpty();
+ }
+
+ public boolean isNotEmpty() {
+ return !isEmpty();
+ }
+
+ public static MultiResponse buildSuccess() {
+ MultiResponse response = new MultiResponse();
+ response.setSuccess(true);
+ return response;
+ }
+
+ public static MultiResponse buildFailure(String errCode, String errMessage) {
+ MultiResponse response = new MultiResponse();
+ response.setSuccess(false);
+ response.setErrCode(errCode);
+ response.setErrMessage(errMessage);
+ return response;
+ }
+
+ public static MultiResponse of(Collection data) {
+ MultiResponse response = new MultiResponse<>();
+ response.setSuccess(true);
+ response.setData(data);
+ return response;
+ }
+
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/Response.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/Response.java
new file mode 100644
index 000000000..e828ad6db
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/Response.java
@@ -0,0 +1,55 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application.dto;
+
+public class Response {
+ private boolean success;
+
+ private String errCode;
+
+ private String errMessage;
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public String getErrCode() {
+ return errCode;
+ }
+
+ public void setErrCode(String errCode) {
+ this.errCode = errCode;
+ }
+
+ public String getErrMessage() {
+ return errMessage;
+ }
+
+ public void setErrMessage(String errMessage) {
+ this.errMessage = errMessage;
+ }
+
+ @Override
+ public String toString() {
+ return "Response [success=" + success + ", errCode=" + errCode + ", errMessage=" + errMessage + "]";
+ }
+
+ public static Response buildSuccess() {
+ Response response = new Response();
+ response.setSuccess(true);
+ return response;
+ }
+
+ public static Response buildFailure(String errCode, String errMessage) {
+ Response response = new Response();
+ response.setSuccess(false);
+ response.setErrCode(errCode);
+ response.setErrMessage(errMessage);
+ return response;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/SingleResponse.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/SingleResponse.java
new file mode 100644
index 000000000..5312e5a80
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/application/dto/SingleResponse.java
@@ -0,0 +1,41 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application.dto;
+
+public class SingleResponse extends Response {
+
+ private static final long serialVersionUID = 1L;
+
+ private T data;
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ public static SingleResponse buildSuccess() {
+ SingleResponse response = new SingleResponse();
+ response.setSuccess(true);
+ return response;
+ }
+
+ public static SingleResponse buildFailure(String errCode, String errMessage) {
+ SingleResponse response = new SingleResponse();
+ response.setSuccess(false);
+ response.setErrCode(errCode);
+ response.setErrMessage(errMessage);
+ return response;
+ }
+
+ public static SingleResponse of(T data) {
+ SingleResponse response = new SingleResponse<>();
+ response.setSuccess(true);
+ response.setData(data);
+ return response;
+ }
+
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/ApplicationContextHelper.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/ApplicationContextHelper.java
new file mode 100644
index 000000000..982692553
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/ApplicationContextHelper.java
@@ -0,0 +1,55 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ApplicationContextHelper implements ApplicationContextAware {
+ private static ApplicationContext applicationContext;
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ ApplicationContextHelper.applicationContext = applicationContext;
+ }
+
+ public static T getBean(Class targetClz) {
+ T beanInstance = null;
+ //优先按type查
+ try {
+ beanInstance = (T)applicationContext.getBean(targetClz);
+ } catch (Exception e) {
+ }
+ //按name查
+ if (beanInstance == null) {
+ String simpleName = targetClz.getSimpleName();
+ //首字母小写
+ simpleName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
+ beanInstance = (T)applicationContext.getBean(simpleName);
+ }
+ if (beanInstance == null) {
+ throw new RuntimeException("Component " + targetClz + " can not be found in Spring Container");
+ }
+ return beanInstance;
+ }
+
+ public static Object getBean(String claz) {
+ return ApplicationContextHelper.applicationContext.getBean(claz);
+ }
+
+ public static T getBean(String name, Class requiredType) {
+ return ApplicationContextHelper.applicationContext.getBean(name, requiredType);
+ }
+
+ public static T getBean(Class requiredType, Object... params) {
+ return ApplicationContextHelper.applicationContext.getBean(requiredType, params);
+ }
+
+ public static ApplicationContext getApplicationContext() {
+ return applicationContext;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/BizException.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/BizException.java
new file mode 100644
index 000000000..a2d48c3a5
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/BizException.java
@@ -0,0 +1,15 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain;
+
+public class BizException extends RuntimeException{
+
+ public BizException(String errMessage) {
+ super(errMessage);
+ }
+
+ public static BizException of(String errMessage){
+ return new BizException(errMessage);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/DomainFactory.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/DomainFactory.java
new file mode 100644
index 000000000..2d2b33a6c
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/DomainFactory.java
@@ -0,0 +1,12 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain;
+
+public class DomainFactory {
+
+ public static T get(Class entityClz){
+ return ApplicationContextHelper.getBean(entityClz);
+ }
+
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/Entity.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/Entity.java
new file mode 100644
index 000000000..51c899bf0
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/Entity.java
@@ -0,0 +1,18 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain;
+
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.lang.annotation.*;
+
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@Component
+@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public @interface Entity {
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/account/Account.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/account/Account.java
new file mode 100644
index 000000000..33815d8c6
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/account/Account.java
@@ -0,0 +1,96 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.account;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import ${package}.domain.BizException;
+import ${package}.domain.DomainFactory;
+import ${package}.domain.Entity;
+import ${package}.domain.charge.*;
+import ${package}.domain.charge.chargeplan.BasicChargePlan;
+import ${package}.domain.charge.chargeplan.ChargePlan;
+import ${package}.domain.charge.chargerule.ChargeRuleFactory;
+import ${package}.domain.charge.chargerule.CompositeChargeRule;
+import ${package}.domain.gateway.AccountGateway;
+import jakarta.annotation.Resource;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Data
+@Entity
+@Slf4j
+public class Account {
+ /**
+ * 用户号码
+ */
+ private long phoneNo;
+
+ /**
+ * 账户余额
+ */
+ private Money remaining;
+
+ /**
+ * 账户所拥有的套餐
+ */
+ @JsonIgnore
+ private List chargePlanList = new ArrayList<>();;
+
+ @Resource
+ private AccountGateway accountGateway;
+
+ private String name;
+
+ public Account(){
+
+ }
+
+ public Account(long phoneNo, Money amount, List chargePlanList){
+ this.phoneNo = phoneNo;
+ this.remaining = amount;
+ this.chargePlanList = chargePlanList;
+ }
+
+ public static Account valueOf(long phoneNo, Money amount) {
+ Account account = DomainFactory.get(Account.class);
+ account.setPhoneNo(phoneNo);
+ account.setRemaining(amount);
+ account.chargePlanList.add(new BasicChargePlan());
+ return account;
+ }
+
+ /**
+ * 检查账户余额是否足够
+ */
+ public void checkRemaining() {
+ if (remaining.isLessThan(Money.of(0))) {
+ throw BizException.of(this.phoneNo + " has insufficient amount");
+ }
+ }
+
+ public List charge(ChargeContext ctx) {
+ CompositeChargeRule compositeChargeRule = ChargeRuleFactory.get(chargePlanList);
+ List chargeRecords = compositeChargeRule.doCharge(ctx);
+ log.debug("Charges: "+ chargeRecords);
+
+ //跟新账户系统
+ accountGateway.sync(phoneNo, chargeRecords);
+ return chargeRecords;
+ }
+
+ @Override
+ public String toString() {
+ return "Account{" +
+ "phoneNo=" + phoneNo +
+ ", remaining=" + remaining +
+ ", chargePlanList=" + chargePlanList +
+ ", name=" + name +
+ '}';
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/account/AccountDomainService.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/account/AccountDomainService.java
new file mode 100644
index 000000000..233e36e56
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/account/AccountDomainService.java
@@ -0,0 +1,24 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.account;
+
+import ${package}.domain.charge.Session;
+import ${package}.domain.gateway.AccountGateway;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class AccountDomainService {
+
+ @Resource
+ private AccountGateway accountGateway;
+
+ public void canSessionStart(Session session){
+ Account callingAccount = accountGateway.getAccount(session.getCallingPhoneNo());
+ Account calledAccount = accountGateway.getAccount(session.getCalledPhoneNo());
+ callingAccount.checkRemaining();
+ calledAccount.checkRemaining();
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/CallType.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/CallType.java
new file mode 100644
index 000000000..dacd18139
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/CallType.java
@@ -0,0 +1,15 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge;
+
+public enum CallType {
+ /**
+ * 主叫
+ */
+ CALLING,
+ /**
+ * 被叫
+ */
+ CALLED
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/ChargeContext.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/ChargeContext.java
new file mode 100644
index 000000000..c4ae1ca60
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/ChargeContext.java
@@ -0,0 +1,70 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge;
+
+import ${package}.domain.account.Account;
+import lombok.Data;
+
+@Data
+public class ChargeContext {
+
+ /**
+ * 本次通话的Session
+ */
+ public Session session;
+
+ /**
+ * 呼叫类型
+ */
+ public CallType callType;
+ /**
+ * 账号号码
+ */
+ public long phoneNo;
+
+ /**
+ * 通话另一端号码
+ */
+ public long otherSidePhoneNo;
+
+ /**
+ * 当前需要被扣费的时长
+ */
+ public int durationToCharge;
+
+ /**
+ * 被Charge的账号
+ */
+ public Account account;
+
+ public ChargeContext(CallType callType, long phoneNo, long otherSidePhoneNo, int durationToCharge) {
+ this.callType = callType;
+ this.phoneNo = phoneNo;
+ this.otherSidePhoneNo = otherSidePhoneNo;
+ this.durationToCharge = durationToCharge;
+ }
+
+ public boolean needCharge(){
+ return durationToCharge >0;
+ }
+
+ public boolean isCalling(){
+ return CallType.CALLING == this.callType;
+ }
+
+ public boolean isCalled(){
+ return CallType.CALLED == this.callType;
+ }
+
+ @Override
+ public String toString() {
+ return "ChargeContext{" +
+ "callType=" + callType +
+ ", phoneNo=" + phoneNo +
+ ", otherSidePhoneNo=" + otherSidePhoneNo +
+ ", durationToCharge=" + durationToCharge +
+ ", account=" + account +
+ '}';
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/ChargeRecord.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/ChargeRecord.java
new file mode 100644
index 000000000..3dac1eff9
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/ChargeRecord.java
@@ -0,0 +1,71 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge;
+
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+import lombok.Data;
+
+import jakarta.persistence.*;
+import java.util.Date;
+
+@Entity
+@Table(name = "charge_record")
+@Data
+public class ChargeRecord {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long Id;
+
+ private String sessionId;
+
+ private long phoneNo;
+
+ /**
+ * 呼叫类型
+ */
+ @Enumerated(EnumType.STRING)
+ private CallType callType;
+
+ /**
+ * 计费记录所对应的呼叫时长
+ */
+ private int chargeDuration;
+
+ /**
+ * 所属计费套餐
+ */
+ @Enumerated(EnumType.STRING)
+ private ChargePlanType chargePlanType;
+
+ private Money cost;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ public Date createTime;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ public Date updateTime;
+
+ public ChargeRecord() {
+ }
+
+ public ChargeRecord(long phoneNo, CallType callType, int chargeDuration, ChargePlanType chargePlanType, Money cost) {
+ this.phoneNo = phoneNo;
+ this.callType = callType;
+ this.chargeDuration = chargeDuration;
+ this.chargePlanType = chargePlanType;
+ this.cost = cost;
+ }
+
+ @Override
+ public String toString() {
+ return "Charge{" +
+ "phoneNo=" + phoneNo +
+ ", callType=" + callType +
+ ", chargeDuration=" + chargeDuration +
+ ", chargePlanType=" + chargePlanType +
+ ", cost=" + cost +
+ '}';
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/Money.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/Money.java
new file mode 100644
index 000000000..8791b621f
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/Money.java
@@ -0,0 +1,50 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge;
+
+
+import lombok.Data;
+
+import java.util.Objects;
+
+/**
+ * 这个Money是简化版的,真实场景应该用BigDecimal
+ */
+@Data
+public class Money {
+
+ /**
+ * 单位是角,1代表0.1元, 10代表1元
+ */
+ private int amount;
+
+ public Money(int amount) {
+ this.amount = amount;
+ }
+
+ public static Money of(int amount){
+ return new Money(amount);
+ }
+
+ public boolean isLessThan(Money money){
+ return this.amount <= money.getAmount();
+ }
+
+ public void minus(Money money){
+ this.amount = this.amount - money.getAmount();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Money money = (Money) o;
+ return amount == money.amount;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(amount);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/MoneyConverter.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/MoneyConverter.java
new file mode 100644
index 000000000..5d25a5610
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/MoneyConverter.java
@@ -0,0 +1,21 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge;
+
+
+import jakarta.persistence.AttributeConverter;
+import jakarta.persistence.Converter;
+
+@Converter(autoApply = true)
+public class MoneyConverter implements AttributeConverter {
+ @Override
+ public Long convertToDatabaseColumn(Money entityData) {
+ return Long.valueOf(entityData.getAmount());
+ }
+
+ @Override
+ public Money convertToEntityAttribute(Long dbData) {
+ return Money.of(dbData.intValue());
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/Session.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/Session.java
new file mode 100644
index 000000000..f3197db36
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/Session.java
@@ -0,0 +1,42 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class Session {
+ private String sessionId;
+
+ /**
+ * 主叫电话号码
+ */
+ private long callingPhoneNo;
+
+ /**
+ * 被叫电话号码
+ */
+ private long calledPhoneNo;
+
+ /**
+ * 当前通话已扣费的时长
+ *
+ */
+ private int chargedDuration;
+
+ /**
+ * 当前通话产生的Charge记录
+ */
+ private List chargeRecordList = new ArrayList<>();
+
+ public Session(String sessionId, long callingPhoneNo, long calledPhoneNo) {
+ this.sessionId = sessionId;
+ this.callingPhoneNo = callingPhoneNo;
+ this.calledPhoneNo = calledPhoneNo;
+ }
+
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/BasicChargePlan.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/BasicChargePlan.java
new file mode 100644
index 000000000..1e6658c81
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/BasicChargePlan.java
@@ -0,0 +1,33 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargeplan;
+
+public class BasicChargePlan extends ChargePlan{
+
+ public BasicChargePlan(){
+ this.priority = 0;
+ }
+
+ @Override
+ public BasicChargeFee getResource() {
+ return new BasicChargeFee();
+ }
+
+ @Override
+ public ChargePlanType getType() {
+ return ChargePlanType.BASIC;
+ }
+
+ public static class BasicChargeFee implements Resource{
+ /**
+ * 主叫单价。单位是角,5表示0.5元每分钟
+ */
+ public final int CALLING_PRICE = 5;
+
+ /**
+ * 主叫单价。单位是角,4表示0.4元每分钟
+ */
+ public final int CALLED_PRICE = 4;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/ChargePlan.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/ChargePlan.java
new file mode 100644
index 000000000..b219b6d99
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/ChargePlan.java
@@ -0,0 +1,33 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargeplan;
+
+public abstract class ChargePlan implements Comparable{
+
+ protected int priority;
+
+ public abstract T getResource();
+
+ public abstract ChargePlanType getType();
+
+ public ChargePlan(){
+
+ }
+ /**
+ * 不同套餐之间的优先级关系
+ * @param other the object to be compared.
+ * @return
+ */
+ @Override
+ public int compareTo(ChargePlan other) {
+ return other.priority - this.priority;
+ }
+
+ @Override
+ public String toString() {
+ return "ChargePlan{chargeType=" + getType()+
+ ", priority=" + priority +
+ '}';
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/ChargePlanType.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/ChargePlanType.java
new file mode 100644
index 000000000..b3bcc6c7f
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/ChargePlanType.java
@@ -0,0 +1,19 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargeplan;
+
+public enum ChargePlanType {
+ /**
+ * 基础套餐
+ */
+ BASIC,
+ /**
+ * 固定时常套餐
+ */
+ FIXED_TIME,
+ /**
+ * 家庭套餐
+ */
+ FAMILY
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/FamilyChargePlan.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/FamilyChargePlan.java
new file mode 100644
index 000000000..c8e8e8668
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/FamilyChargePlan.java
@@ -0,0 +1,41 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargeplan;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class FamilyChargePlan extends ChargePlan {
+
+ public FamilyChargePlan() {
+ this.priority = 2;
+ }
+
+ @Override
+ public FamilyMember getResource() {
+ return new FamilyMember();
+ }
+
+ @Override
+ public ChargePlanType getType() {
+ return ChargePlanType.FAMILY;
+ }
+
+ public static class FamilyMember implements Resource{
+ private Set familyMembers = new HashSet<>();
+
+ /**
+ * Mock here, 真实场景,情亲号码肯定也是从外系统获取的
+ */
+ public FamilyMember() {
+ familyMembers.add(13681874561L);
+ familyMembers.add(15921582125L);
+ }
+
+ public boolean isMember(long phoneNo) {
+ return familyMembers.contains(phoneNo);
+ }
+ }
+}
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/FixedTimeChangePlan.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/FixedTimeChangePlan.java
new file mode 100644
index 000000000..ea4267116
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/FixedTimeChangePlan.java
@@ -0,0 +1,68 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargeplan;
+
+public class FixedTimeChangePlan extends ChargePlan{
+
+ public FixedTimeChangePlan() {
+ this.priority=1;
+ }
+
+ @Override
+ public FreeCallTime getResource() {
+ return new FreeCallTime();
+ }
+
+ @Override
+ public ChargePlanType getType() {
+ return ChargePlanType.FIXED_TIME;
+ }
+
+ public static class FreeCallTime implements Resource{
+ public static int FREE_CALLING_TIME = 200;
+ public static int FREE_CALLED_TIME = 200;
+
+ public boolean isCallingTimeRemaining(){
+ return FREE_CALLING_TIME > 0;
+ }
+
+ /**
+ * 扣减固定时长套餐的费用
+ * @param duration 扣减时长
+ * @return 剩余还需要扣减的时长
+ */
+ public int chargeFreeCallingTime(int duration){
+ if(duration > FREE_CALLING_TIME){
+ int durationToCharge = duration - FREE_CALLING_TIME;
+ FREE_CALLING_TIME = 0;
+ return durationToCharge;
+ }
+ else{
+ FREE_CALLING_TIME = FREE_CALLING_TIME - duration;
+ return 0;
+ }
+ }
+
+ public boolean isCalledTimeRemaining(){
+ return FREE_CALLED_TIME > 0;
+ }
+
+ /**
+ * 扣减固定时长套餐的费用
+ * @param duration 扣减时长
+ * @return 剩余还需要扣减的时长
+ */
+ public int chargeFreeCalledTime(int duration){
+ if(duration > FREE_CALLED_TIME){
+ int durationToCharge = duration - FREE_CALLED_TIME;
+ FREE_CALLED_TIME = 0;
+ return durationToCharge;
+ }
+ else{
+ FREE_CALLED_TIME = FREE_CALLED_TIME - duration;
+ return 0;
+ }
+ }
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/Resource.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/Resource.java
new file mode 100644
index 000000000..a9fabfed9
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargeplan/Resource.java
@@ -0,0 +1,10 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargeplan;
+
+/**
+ * 套餐背后所绑定的资源
+ */
+public interface Resource {
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/AbstractChargeRule.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/AbstractChargeRule.java
new file mode 100644
index 000000000..a6c36298d
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/AbstractChargeRule.java
@@ -0,0 +1,17 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargerule;
+
+import ${package}.domain.charge.chargeplan.ChargePlan;
+
+public abstract class AbstractChargeRule implements ChargeRule{
+ protected ChargePlan chargePlan;
+
+ @Override
+ public void belongsTo(ChargePlan chargePlan){
+ this.chargePlan = chargePlan;
+ }
+
+
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/BasicChargeRule.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/BasicChargeRule.java
new file mode 100644
index 000000000..2bebbccb0
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/BasicChargeRule.java
@@ -0,0 +1,37 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargerule;
+
+import ${package}.domain.charge.*;
+import ${package}.domain.charge.chargeplan.BasicChargePlan;
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+public class BasicChargeRule extends AbstractChargeRule{
+ @Override
+ public ChargeRecord doCharge(ChargeContext ctx) {
+ if(!ctx.needCharge()){
+ log.debug("No need charge for : "+ctx);
+ return null;
+ }
+ BasicChargePlan basicChargePlan = (BasicChargePlan)chargePlan;
+ BasicChargePlan.BasicChargeFee chargeFee = basicChargePlan.getResource();
+ Money cost;
+ int duration = ctx.durationToCharge;
+ if (ctx.callType == CallType.CALLING) {
+ cost = Money.of(duration * chargeFee.CALLING_PRICE);
+ } else {
+ cost = Money.of(duration * chargeFee.CALLED_PRICE);
+ }
+ ChargeRecord chargeRecord = new ChargeRecord(ctx.phoneNo, ctx.callType, duration, ChargePlanType.BASIC, cost);
+
+ //在账号上扣减费用
+ ctx.account.getRemaining().minus(cost);
+ ctx.setDurationToCharge(0);
+ return chargeRecord;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/ChargeRule.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/ChargeRule.java
new file mode 100644
index 000000000..9002e42db
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/ChargeRule.java
@@ -0,0 +1,15 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargerule;
+
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.ChargeContext;
+import ${package}.domain.charge.chargeplan.ChargePlan;
+
+public interface ChargeRule {
+ ChargeRecord doCharge(ChargeContext ctx);
+
+ void belongsTo(ChargePlan chargePlan);
+
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/ChargeRuleFactory.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/ChargeRuleFactory.java
new file mode 100644
index 000000000..0bf2af683
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/ChargeRuleFactory.java
@@ -0,0 +1,36 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargerule;
+
+import ${package}.domain.ApplicationContextHelper;
+import ${package}.domain.charge.chargeplan.ChargePlan;
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ChargeRuleFactory {
+ public static CompositeChargeRule get(List chargePlanList) {
+ //按套餐的优先级进行排序
+ Collections.sort(chargePlanList);
+
+ List chargeRules = new ArrayList<>();
+ for (ChargePlan chargePlan : chargePlanList) {
+ ChargeRule chargeRule;
+ if (chargePlan.getType() == ChargePlanType.FAMILY) {
+ chargeRule = ApplicationContextHelper.getBean(FamilyChargeRule.class);
+ } else if (chargePlan.getType() == ChargePlanType.FIXED_TIME) {
+ chargeRule = ApplicationContextHelper.getBean(FixedTimeChargeRule.class);
+ } else {
+ chargeRule = ApplicationContextHelper.getBean(BasicChargeRule.class);
+ }
+ chargeRule.belongsTo(chargePlan);
+ chargeRules.add(chargeRule);
+ }
+ CompositeChargeRule compositeChargeRule = new CompositeChargeRule();
+ compositeChargeRule.chargeRules = chargeRules;
+ return compositeChargeRule;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/CompositeChargeRule.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/CompositeChargeRule.java
new file mode 100644
index 000000000..f9fdcc0ae
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/CompositeChargeRule.java
@@ -0,0 +1,34 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargerule;
+
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.ChargeContext;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 为了应对套餐组合
+ * 组合模式(Composite pattern)
+ */
+public class CompositeChargeRule {
+ public List chargeRules;
+
+ public List doCharge(ChargeContext chargeContext){
+ List chargeRecords = new ArrayList<>();
+ for(ChargeRule chargeRule : chargeRules){
+ ChargeRecord chargeRecord = chargeRule.doCharge(chargeContext);
+ if(chargeRecord != null){
+ chargeRecord.setSessionId(chargeContext.getSession().getSessionId());
+ //fill fields for persistence needs
+ chargeRecord.setCreateTime(new Date());
+ chargeRecord.setUpdateTime(new Date());
+ chargeRecords.add(chargeRecord);
+ }
+ }
+ return chargeRecords;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/FamilyChargeRule.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/FamilyChargeRule.java
new file mode 100644
index 000000000..058ac34e9
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/FamilyChargeRule.java
@@ -0,0 +1,30 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargerule;
+
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.ChargeContext;
+import ${package}.domain.charge.Money;
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+import ${package}.domain.charge.chargeplan.FamilyChargePlan;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+public class FamilyChargeRule extends AbstractChargeRule {
+
+ @Override
+ public ChargeRecord doCharge(ChargeContext ctx) {
+ FamilyChargePlan familyChargePlan = (FamilyChargePlan) chargePlan;
+ FamilyChargePlan.FamilyMember familyMember = familyChargePlan.getResource();
+ if (familyMember.isMember(ctx.otherSidePhoneNo)) {
+ log.debug("Family Charge plan for Account : " + ctx.account);
+ ChargeRecord chargeRecord = new ChargeRecord(ctx.phoneNo, ctx.callType, ctx.durationToCharge, ChargePlanType.FAMILY, Money.of(0));
+ ctx.setDurationToCharge(0);
+ return chargeRecord;
+ }
+ return null;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/FixedTimeChargeRule.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/FixedTimeChargeRule.java
new file mode 100644
index 000000000..a2d6ed5d1
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/charge/chargerule/FixedTimeChargeRule.java
@@ -0,0 +1,41 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.charge.chargerule;
+
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.ChargeContext;
+import ${package}.domain.charge.Money;
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+import ${package}.domain.charge.chargeplan.FixedTimeChangePlan;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+public class FixedTimeChargeRule extends AbstractChargeRule {
+ @Override
+ public ChargeRecord doCharge(ChargeContext ctx) {
+ if(!ctx.needCharge()){
+ log.debug("No need charge for : "+ctx);
+ return null;
+ }
+ FixedTimeChangePlan fixedTimeChangePlan = (FixedTimeChangePlan) chargePlan;
+ FixedTimeChangePlan.FreeCallTime freeCallTime = fixedTimeChangePlan.getResource();
+ if (ctx.isCalling() && freeCallTime.isCallingTimeRemaining()) {
+ int leftDuration = freeCallTime.chargeFreeCallingTime(ctx.durationToCharge);
+ log.debug("Calling Left Duration after FixedTimeCharge : " + leftDuration);
+ ChargeRecord chargeRecord = new ChargeRecord(ctx.phoneNo, ctx.callType, ctx.durationToCharge - leftDuration, ChargePlanType.FIXED_TIME, Money.of(0));
+ ctx.setDurationToCharge(leftDuration);
+ return chargeRecord;
+ }
+ if (ctx.isCalled() && freeCallTime.isCalledTimeRemaining()) {
+ int leftDuration = freeCallTime.chargeFreeCalledTime(ctx.durationToCharge);
+ log.debug("Called Left Duration after FixedTimeCharge : " + leftDuration);
+ ChargeRecord chargeRecord = new ChargeRecord(ctx.phoneNo, ctx.callType, ctx.durationToCharge - leftDuration, ChargePlanType.FIXED_TIME, Money.of(0));
+ ctx.setDurationToCharge(leftDuration);
+ return chargeRecord;
+ }
+ return null;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/AccountGateway.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/AccountGateway.java
new file mode 100644
index 000000000..02df4d91e
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/AccountGateway.java
@@ -0,0 +1,33 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.gateway;
+
+import ${package}.domain.account.Account;
+import ${package}.domain.charge.ChargeRecord;
+
+import java.util.List;
+
+/**
+ * 跟账户系统交互的网关(Gateway)
+ *
+ * @version 1.0
+ */
+public interface AccountGateway {
+
+ /**
+ * 根据用户号码获取账户信息(含计费项余额等信息)
+ *
+ * @param phoneNo 电话号码
+ * @return 账户信息
+ */
+ Account getAccount(long phoneNo);
+
+ /**
+ * 将扣费记录同步到账户中
+ *
+ * @param phoneNo 电话号码
+ * @param records 扣费记录
+ */
+ void sync(long phoneNo, List records);
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/ChargeGateway.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/ChargeGateway.java
new file mode 100644
index 000000000..7f8d51b20
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/ChargeGateway.java
@@ -0,0 +1,19 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.gateway;
+
+import ${package}.domain.charge.ChargeRecord;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ChargeGateway extends JpaRepository {
+ public List findBySessionId(String sessionId);
+
+ public ChargeRecord getBySessionId(String sessionId);
+
+ public List findByPhoneNo(long phoneNo);
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/SessionGateway.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/SessionGateway.java
new file mode 100644
index 000000000..de64e3045
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/domain/gateway/SessionGateway.java
@@ -0,0 +1,15 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain.gateway;
+
+import ${package}.domain.charge.Session;
+
+public interface SessionGateway {
+
+ void create(Session session);
+
+ Session get(String sessionId);
+
+ void end(String sessionId);
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/AccountGatewayImpl.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/AccountGatewayImpl.java
new file mode 100644
index 000000000..87ceeaf2b
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/AccountGatewayImpl.java
@@ -0,0 +1,49 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import ${package}.domain.account.Account;
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.Money;
+import ${package}.domain.gateway.AccountGateway;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestClient;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component
+@Slf4j
+public class AccountGatewayImpl implements AccountGateway {
+ private static final String GET_ACCOUNT_PATH = "/v1/api/account/{account}";
+ private static final String SYNC_ACCOUNT_PATH = "/v1/api/account/account/{account}/sync";
+
+ private Map accountMap = new HashMap<>();
+
+ @Autowired
+ private RestClient restClient;
+
+ @Override
+ public Account getAccount(long phoneNo) {
+ Account account = restClient.get()
+ .uri(GET_ACCOUNT_PATH, phoneNo)
+ .accept(MediaType.APPLICATION_JSON)
+ .retrieve()
+ .body(Account.class);
+
+ return account;
+ }
+
+ @Override
+ public void sync(long phoneNo, List records) {
+ // 更新账户系统
+ log.info("sync account info, to be implemented");
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/RestClientBean.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/RestClientBean.java
new file mode 100644
index 000000000..59b0eff29
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/RestClientBean.java
@@ -0,0 +1,21 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestClient;
+
+@Configuration
+public class RestClientBean {
+
+ @Value("${symbol_dollar}{REMOTE_BASE_URI:http://localhost:8080}")
+ String baseURI;
+
+ @Bean
+ RestClient restClient() {
+ return RestClient.create(baseURI);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/SessionGatewayImpl.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/SessionGatewayImpl.java
new file mode 100644
index 000000000..0b9e1351b
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/java/infrastructure/SessionGatewayImpl.java
@@ -0,0 +1,33 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import ${package}.domain.BizException;
+import ${package}.domain.charge.Session;
+import ${package}.domain.gateway.SessionGateway;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class SessionGatewayImpl implements SessionGateway {
+ private Map sessionMap = new HashMap<>();
+
+ @Override
+ public void create(Session session) {
+ sessionMap.put(session.getSessionId(), session);
+ }
+
+ @Override
+ public Session get(String sessionId) {
+ return sessionMap.get(sessionId);
+ }
+
+ @Override
+ public void end(String sessionId) {
+ //真实场景是逻辑删除,比如把session的状态标记为“已结束”。
+ sessionMap.remove(sessionId);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/resources/application.yml b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/resources/application.yml
new file mode 100644
index 000000000..ef412dde2
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/resources/application.yml
@@ -0,0 +1,18 @@
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://${MYSQL_SERVER:localhost}:${MYSQL_PORT:3306}/${MYSQL_DB_NAME:chargeDB}?serverTimezone=UTC
+ #如果运行出错,可以把连接写成下面的路径进行测试
+ #url: jdbc:mysql://localhost:3306/blogDB?useUnicode=true&characterEncoding=utf-8
+ username: ${MYSQL_USER_TEST:root}
+ password: ${MYSQL_PASSWORD_TEST:root}
+ jpa:
+ hibernate:
+ ddl-auto: update
+ show-sql: true
+
+server:
+ port: 8081
+
+my-name: default
+my-age: default
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/resources/logback.xml b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/resources/logback.xml
new file mode 100644
index 000000000..80e55994a
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/main/resources/logback.xml
@@ -0,0 +1,26 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+
+
+
+
+
+ %-4relative [%thread] %-5level %logger{35} - %msg%n
+ utf8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/charge.http b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/charge.http
new file mode 100644
index 000000000..47ab59f42
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/charge.http
@@ -0,0 +1,20 @@
+### list charge records by sessionId
+GET http://localhost:8080/123145/chargeRecords
+Accept: application/json
+
+### end session
+POST http://localhost:8080/session/123145/end?duration=10
+Content-Type: application/x-www-form-urlencoded
+
+duration=10
+
+### do charge
+POST http://localhost:8080/session/123145/charge?duration=10
+
+
+### begin Session
+POST http://localhost:8080/session/123145/begin?callingPhoneNo=13681874561&calledPhoneNo=15921252125
+
+<> 2022-11-03T150743.200.json
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/CleanArchTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/CleanArchTest.java
new file mode 100644
index 000000000..a2198e28c
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/CleanArchTest.java
@@ -0,0 +1,27 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package};
+
+import org.junit.jupiter.api.Test;
+
+public class CleanArchTest {
+ @Test
+ public void protect_clean_arch() {
+// JavaClasses classes = new ClassFileImporter()
+// .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
+// .importPackages("${package}");
+//
+// layeredArchitecture()
+// .consideringOnlyDependenciesInLayers()
+// .layer("adapter").definedBy("${package}.adapter")
+// .layer("application").definedBy("${package}.application")
+// .layer("domain").definedBy("${package}.domain")
+// .layer("infrastructure").definedBy("${package}.infrastructure")
+// .whereLayer("adapter").mayNotBeAccessedByAnyLayer()
+// //.whereLayer("domain").mayOnlyBeAccessedByLayers("application", "infrastructure")
+// .as("The layer dependencies must be respected")
+// .because("we must follow the Clean Architecture principle")
+// .check(classes);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/TestsContainerBoot.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/TestsContainerBoot.java
new file mode 100644
index 000000000..a5f894d31
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/TestsContainerBoot.java
@@ -0,0 +1,12 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package};
+
+import com.alibaba.cola.test.TestsContainer;
+
+public class TestsContainerBoot {
+ public static void main(String[] args) {
+ TestsContainer.start();
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/application/ChargeServiceTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/application/ChargeServiceTest.java
new file mode 100644
index 000000000..407ff6b7b
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/application/ChargeServiceTest.java
@@ -0,0 +1,69 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.application;
+
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import ${package}.Application;
+import ${package}.application.dto.BeginSessionRequest;
+import ${package}.domain.BizException;
+import ${package}.domain.gateway.AccountGateway;
+import ${package}.domain.gateway.SessionGateway;
+import ${package}.infrastructure.WireMockRegister;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+
+
+@SpringBootTest
+@ContextConfiguration(classes = Application.class)
+@WireMockTest(httpPort = 8080)
+public class ChargeServiceTest {
+
+ @Autowired
+ private ChargeServiceI chargeService;
+
+ @Autowired
+ private SessionGateway sessionGateway;
+
+ @Autowired
+ private AccountGateway accountGateway;
+
+
+ @Test
+ public void test_session_create(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_account.json");
+
+ BeginSessionRequest request = new BeginSessionRequest();
+ String sessionId = "00002";
+ request.setSessionId(sessionId);
+ request.setCallingPhoneNo(13681874563L);
+ request.setCalledPhoneNo(15921582125L);
+
+ chargeService.begin(request);
+
+ Assertions.assertEquals(sessionId, sessionGateway.get(sessionId).getSessionId());
+ }
+
+ @Test
+ public void test_remaining_insufficient(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_insufficient_account.json");
+
+ BeginSessionRequest request = new BeginSessionRequest();
+ String sessionId = "00003";
+ request.setSessionId(sessionId);
+ request.setCallingPhoneNo(13681874561L);
+ request.setCalledPhoneNo(15921582125L);
+
+ Exception exception = Assertions.assertThrows(BizException.class, () -> {
+ chargeService.begin(request);
+ });
+ String expectedMsg = "has insufficient amount";
+ String actualMsg = exception.getMessage();
+ Assertions.assertTrue(actualMsg.contains(expectedMsg));
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/ChargeRecordPlanTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/ChargeRecordPlanTest.java
new file mode 100644
index 000000000..7dad668d7
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/ChargeRecordPlanTest.java
@@ -0,0 +1,37 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain;
+
+
+import ${package}.domain.charge.chargeplan.BasicChargePlan;
+import ${package}.domain.charge.chargeplan.ChargePlan;
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+import ${package}.domain.charge.chargeplan.FamilyChargePlan;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ChargeRecordPlanTest {
+
+ @Test
+ public void test_priority(){
+ ChargePlan basicChargePlan = new BasicChargePlan();
+ ChargePlan familyChargePlan = new FamilyChargePlan();
+ ChargePlan fixedTimeChargePlan = new FamilyChargePlan();
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(basicChargePlan);
+ chargePlanList.add(familyChargePlan);
+ chargePlanList.add(fixedTimeChargePlan);
+
+ Collections.sort(chargePlanList);
+
+ System.out.println(chargePlanList.get(0));
+ Assertions.assertEquals(ChargePlanType.FAMILY, chargePlanList.get(0).getType());
+
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/ChargeRecordRuleTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/ChargeRecordRuleTest.java
new file mode 100644
index 000000000..68e6117e8
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/ChargeRecordRuleTest.java
@@ -0,0 +1,94 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain;
+
+import ${package}.domain.account.Account;
+import ${package}.domain.charge.CallType;
+import ${package}.domain.charge.ChargeContext;
+import ${package}.domain.charge.Money;
+import ${package}.domain.charge.chargeplan.BasicChargePlan;
+import ${package}.domain.charge.chargeplan.ChargePlan;
+import ${package}.domain.charge.chargeplan.FamilyChargePlan;
+import ${package}.domain.charge.chargeplan.FixedTimeChangePlan;
+import ${package}.domain.charge.chargerule.BasicChargeRule;
+import ${package}.domain.charge.chargerule.FamilyChargeRule;
+import ${package}.domain.charge.chargerule.FixedTimeChargeRule;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+public class ChargeRecordRuleTest {
+
+ @Test
+ public void test_basic_charge_rule(){
+ //prepare
+ ChargePlan chargePlan = new BasicChargePlan();
+ Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 20);
+ ctx.account = account;
+ System.out.println("Account before charge: "+ account);
+
+ //do
+ BasicChargeRule basicChargeRule = new BasicChargeRule();
+ basicChargeRule.belongsTo(chargePlan);
+ basicChargeRule.doCharge(ctx);
+
+ //check
+ System.out.println("Account after charge: "+ account);
+ Assertions.assertEquals( Money.of(100), ctx.account.getRemaining());
+ Assertions.assertEquals( 0, ctx.getDurationToCharge());
+ }
+
+ @Test
+ public void test_family_charge_rule(){
+ //prepare
+ FamilyChargePlan chargePlan = new FamilyChargePlan();
+ Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 20);
+ ctx.account = account;
+ System.out.println("Account before charge: "+ account);
+
+ //do
+ FamilyChargeRule familyChargeRule = new FamilyChargeRule();
+ familyChargeRule.belongsTo(chargePlan);
+ familyChargeRule.doCharge(ctx);
+
+ //check
+ System.out.println("Account after charge: "+ account);
+ Assertions.assertEquals( Money.of(200), ctx.account.getRemaining());
+ Assertions.assertEquals( 0, ctx.getDurationToCharge());
+ }
+
+ @Test
+ public void test_fixed_time_charge_rule(){
+ //prepare
+ FixedTimeChangePlan chargePlan = new FixedTimeChangePlan();
+ Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 180);
+ ctx.account = account;
+ System.out.println("Account before charge: "+ account);
+
+ //do
+ FixedTimeChargeRule fixedTimeChargeRule = new FixedTimeChargeRule();
+ fixedTimeChargeRule.belongsTo(chargePlan);
+ fixedTimeChargeRule.doCharge(ctx);
+
+ //check
+ System.out.println("Account after charge: "+ account);
+ Assertions.assertEquals( true, chargePlan.getResource().isCallingTimeRemaining());
+ Assertions.assertEquals( 0, ctx.getDurationToCharge());
+
+ // come a new charge
+ ChargeContext ctx2 = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 40);
+ ctx2.account = account;
+ fixedTimeChargeRule.doCharge(ctx2);
+ Assertions.assertEquals( false, chargePlan.getResource().isCallingTimeRemaining());
+ Assertions.assertEquals( 20, ctx2.getDurationToCharge());
+
+ //reset fixed time
+ FixedTimeChangePlan.FreeCallTime.FREE_CALLED_TIME = 200;
+ FixedTimeChangePlan.FreeCallTime.FREE_CALLING_TIME = 200;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/CompositeChargeRuleTestRecord.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/CompositeChargeRuleTestRecord.java
new file mode 100644
index 000000000..958f506d8
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/domain/CompositeChargeRuleTestRecord.java
@@ -0,0 +1,94 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.domain;
+
+import ${package}.Application;
+import ${package}.domain.account.Account;
+import ${package}.domain.charge.*;
+import ${package}.domain.charge.chargeplan.BasicChargePlan;
+import ${package}.domain.charge.chargeplan.ChargePlan;
+import ${package}.domain.charge.chargeplan.FamilyChargePlan;
+import ${package}.domain.charge.chargeplan.FixedTimeChangePlan;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@SpringBootTest
+@ContextConfiguration(classes = Application.class)
+public class CompositeChargeRuleTestRecord {
+
+ private long callingPhoneNo = 13681874561L;
+ private long calledPhoneNo = 15921582125L;
+
+ @Test
+ public void test_basic_and_fixedTime_charge_rule(){
+ // prepare
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(new BasicChargePlan());
+ chargePlanList.add(new FixedTimeChangePlan());
+ Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
+ account.setChargePlanList(chargePlanList);
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
+ String sessionId = UUID.randomUUID().toString();
+ Session session = new Session(sessionId, callingPhoneNo, calledPhoneNo);
+ ctx.setSession(session);
+ ctx.account = account;
+
+ // do
+ List chargeRecords = account.charge(ctx);
+ System.out.println("Account after charge: "+ account);
+ // check
+ Assertions.assertEquals(2, chargeRecords.size());
+ }
+
+ @Test
+ public void test_basic_and_family_charge_rule(){
+ // prepare
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(new BasicChargePlan());
+ chargePlanList.add(new FamilyChargePlan());
+ Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
+ account.setChargePlanList(chargePlanList);
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
+ String sessionId = UUID.randomUUID().toString();
+ Session session = new Session(sessionId, callingPhoneNo, calledPhoneNo);
+ ctx.setSession(session);
+ ctx.account = account;
+
+ // do
+ List chargeRecords = account.charge(ctx);
+ System.out.println("Account after charge: "+ account);
+ // check
+ Assertions.assertEquals(1, chargeRecords.size());
+ }
+
+ @Test
+ public void test_all_charge_rule(){
+ // prepare
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(new BasicChargePlan());
+ chargePlanList.add(new FamilyChargePlan());
+ chargePlanList.add(new FixedTimeChangePlan());
+ Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
+ account.setChargePlanList(chargePlanList);
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
+ String sessionId = UUID.randomUUID().toString();
+ Session session = new Session(sessionId, callingPhoneNo, calledPhoneNo);
+ ctx.setSession(session);
+ ctx.account = account;
+
+ // do
+ List chargeRecords = account.charge(ctx);
+ System.out.println("Account after charge: "+ account);
+
+ // check
+ Assertions.assertEquals(1, chargeRecords.size());
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/AccountGatewayTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/AccountGatewayTest.java
new file mode 100644
index 000000000..2c6ad2fe1
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/AccountGatewayTest.java
@@ -0,0 +1,36 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import ${package}.Application;
+import ${package}.domain.account.Account;
+import ${package}.domain.charge.Money;
+import ${package}.domain.gateway.AccountGateway;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(classes = Application.class)
+@WireMockTest(httpPort = 8080)
+public class AccountGatewayTest {
+
+ @Autowired
+ AccountGateway accountGateway;
+
+ @Test
+ public void testGetAccount(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_account.json");
+
+ Account account = accountGateway.getAccount(15921582125L);
+ System.out.println("account : " + account);
+
+ Assertions.assertEquals(account.getPhoneNo(), 15921582125L);
+ Assertions.assertEquals(account.getRemaining(), Money.of(400));
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/ChargeRecordRepoTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/ChargeRecordRepoTest.java
new file mode 100644
index 000000000..c93f8a783
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/ChargeRecordRepoTest.java
@@ -0,0 +1,63 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import ${package}.domain.charge.CallType;
+import ${package}.domain.charge.ChargeRecord;
+import ${package}.domain.charge.Money;
+import ${package}.domain.charge.chargeplan.ChargePlanType;
+import ${package}.domain.gateway.ChargeGateway;
+
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+@SpringBootTest
+public class ChargeRecordRepoTest {
+ @Resource
+ private ChargeGateway chargeGateway;
+
+ private String sessionId;
+
+ @BeforeEach
+ public void setup(){
+ sessionId = UUID.randomUUID().toString();
+ }
+
+ @Test
+ public void testSave(){
+ ChargeRecord chargeRecord = new ChargeRecord(13681874561L, CallType.CALLED, 10, ChargePlanType.FAMILY, Money.of(123));
+ chargeRecord.setSessionId(sessionId);
+ chargeRecord.setCreateTime(new Date());
+ chargeRecord.setUpdateTime(new Date());
+ chargeGateway.save(chargeRecord);
+
+ chargeRecord = chargeGateway.getBySessionId(sessionId);
+
+ Assertions.assertEquals(chargeRecord.getSessionId(), sessionId);
+ }
+
+ @Test
+ public void testSaveList(){
+ List chargeRecordList = new ArrayList<>();
+ ChargeRecord chargeRecord1 = new ChargeRecord(13681874561L, CallType.CALLED, 10, ChargePlanType.FAMILY, Money.of(123));
+ chargeRecord1.setSessionId(UUID.randomUUID().toString());
+ ChargeRecord chargeRecord2 = new ChargeRecord(13681874561L, CallType.CALLING, 10, ChargePlanType.FAMILY, Money.of(123));
+ chargeRecord2.setSessionId(UUID.randomUUID().toString());
+ chargeRecordList.add(chargeRecord1);
+ chargeRecordList.add(chargeRecord2);
+ chargeGateway.saveAll(chargeRecordList);
+
+ List result = chargeGateway.findByPhoneNo(13681874561L);
+
+ Assertions.assertEquals(result.size(), 2);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/FixtureLoader.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/FixtureLoader.java
new file mode 100644
index 000000000..92df2cb96
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/FixtureLoader.java
@@ -0,0 +1,30 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.StreamUtils;
+
+public class FixtureLoader {
+
+ public static String loadResource(String resourcePath) {
+ // 创建一个 ClassPathResource 对象
+ ClassPathResource resource = new ClassPathResource(resourcePath);
+
+ // 使用 withResource 来自动关闭输入流
+ String content = "";
+ try (InputStream inputStream = resource.getInputStream()) {
+ content = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e.getMessage());
+ }
+ return content;
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/JSONTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/JSONTest.java
new file mode 100644
index 000000000..2ff38bdfd
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/JSONTest.java
@@ -0,0 +1,29 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import ${package}.domain.account.Account;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class JSONTest {
+
+ @Test
+ public void testJsonBind() {
+ // this will throw exception since account not recognized
+ String badJson = "{${symbol_escape}"account${symbol_escape}":{${symbol_escape}"name${symbol_escape}":${symbol_escape}"frank${symbol_escape}",${symbol_escape}"phoneNo${symbol_escape}":${symbol_escape}"15921582125${symbol_escape}",${symbol_escape}"remaining${symbol_escape}":${symbol_escape}"400${symbol_escape}",${symbol_escape}"chargePlanList${symbol_escape}":[{${symbol_escape}"priority${symbol_escape}":${symbol_escape}"2${symbol_escape}",${symbol_escape}"type${symbol_escape}":${symbol_escape}"fixedTime${symbol_escape}"},{${symbol_escape}"priority${symbol_escape}":${symbol_escape}"1${symbol_escape}",${symbol_escape}"type${symbol_escape}":${symbol_escape}"familyMember${symbol_escape}"}]}}";
+ // this is good
+ String goodJson = "{${symbol_escape}"name${symbol_escape}":${symbol_escape}"frank${symbol_escape}",${symbol_escape}"phoneNo${symbol_escape}":${symbol_escape}"15921582125${symbol_escape}",${symbol_escape}"remaining${symbol_escape}":${symbol_escape}"400${symbol_escape}",${symbol_escape}"chargePlanList${symbol_escape}":[{${symbol_escape}"priority${symbol_escape}":${symbol_escape}"2${symbol_escape}",${symbol_escape}"type${symbol_escape}":${symbol_escape}"fixedTime${symbol_escape}"},{${symbol_escape}"priority${symbol_escape}":${symbol_escape}"1${symbol_escape}",${symbol_escape}"type${symbol_escape}":${symbol_escape}"familyMember${symbol_escape}"}]}";
+
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ Account account = objectMapper.readValue(goodJson, Account.class);
+ Assertions.assertEquals(account.getPhoneNo(), 15921582125L);
+ System.out.println(account);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/SpingBootConfTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/SpingBootConfTest.java
new file mode 100644
index 000000000..35c557f34
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/SpingBootConfTest.java
@@ -0,0 +1,48 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+
+@SpringBootTest
+//use test profile, this will merge application.yml and application-test.yaml.
+//but if you put an application.yml under test/resources, it will replace the project application.yml.
+//the advantage of profile, is that it can inherit and override.
+@ActiveProfiles("test")
+public class SpingBootConfTest {
+
+ @Value("${symbol_dollar}{spring.jpa.show-sql}")
+ private String showSql;
+
+ @Value("${symbol_dollar}{spring.jpa.hibernate.ddl-auto}")
+ private String ddlAuto;
+
+ @Value("${symbol_dollar}{my-name}")
+ private String myName;
+
+ @Value("${symbol_dollar}{my-age}")
+ private String myAge;
+
+ @Value("${symbol_dollar}{my-age-test}")
+ private String myAgeTest;
+
+
+ @Test
+ public void test() {
+ System.out.println("spring.jpa.show-sql : " + showSql);
+ System.out.println("spring.jpa.hibernate.ddl-auto : " + ddlAuto);
+ System.out.println("myName : " + myName);
+ System.out.println("myAge : " + myAge);
+ System.out.println("myAgeTest : " + myAgeTest);
+
+ Assertions.assertEquals("30", myAge);
+ Assertions.assertEquals("40", myAgeTest);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/WireMockBasicTest.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/WireMockBasicTest.java
new file mode 100644
index 000000000..0516138cf
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/WireMockBasicTest.java
@@ -0,0 +1,84 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import ${package}.Application;
+import ${package}.domain.account.Account;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+
+@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@WireMockTest(httpPort = 8080)
+@Slf4j
+public class WireMockBasicTest {
+
+ @Autowired
+ protected WebTestClient webClient;
+
+ @Test
+ public void testWireMockBasic() {
+ // The static DSL will be automatically configured for you
+ stubFor(get("/static-dsl").willReturn(ok()));
+
+ webClient.get()
+ .uri("http://localhost:8080/static-dsl")
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200);
+ }
+
+ @Test
+ public void testWireMockStub(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMock wireMock = wmRuntimeInfo.getWireMock();
+ WireMockRegister.registerStub(wireMock, "/fixture/wiremock/stub_wire_mock_basic.json");
+
+ webClient.get()
+ .uri("http://localhost:8080/v1/wiremock/basic")
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200)
+ .expectHeader()
+ .contentType(MediaType.APPLICATION_JSON);
+
+ System.out.println("wire mock serer port : " + wmRuntimeInfo.getHttpPort());
+ }
+
+ @Test
+ public void testWireMockAccount(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_account.json");
+
+ long phoneNo = 123456789;
+
+ webClient.get()
+ .uri("http://localhost:8080/v1/api/account/"+phoneNo)
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200)
+ .expectHeader()
+ .contentType(MediaType.APPLICATION_JSON)
+ .returnResult(Account.class)
+ .getResponseBody()
+ .map(account -> {
+ log.info(account.toString());
+ Assertions.assertEquals("frank", account.getName());
+ Assertions.assertEquals(phoneNo, account.getPhoneNo());
+ return account;
+ })
+ .subscribe();
+
+ log.info("wire mock serer port : " + wmRuntimeInfo.getHttpPort());
+ }
+
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/WireMockRegister.java b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/WireMockRegister.java
new file mode 100644
index 000000000..a9f54a5f0
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/java/infrastructure/WireMockRegister.java
@@ -0,0 +1,15 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+package ${package}.infrastructure;
+
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.stubbing.StubMapping;
+
+public class WireMockRegister {
+
+ public static void registerStub(WireMock wireMock, String resourcePath){
+ StubMapping stubMapping = StubMapping.buildFrom(FixtureLoader.loadResource(resourcePath));
+ wireMock.register(stubMapping);
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/application-test.yml b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/application-test.yml
new file mode 100644
index 000000000..18a4fd19d
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/application-test.yml
@@ -0,0 +1,17 @@
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ # hard code for test purpose
+ url: jdbc:mysql://localhost:3306/chargeDB?serverTimezone=UTC
+ username: root
+ password: root
+
+ jpa:
+ hibernate:
+ ddl-auto: update
+ show-sql: true
+
+# this will override config in test/resources/application.yml and resources/application.yml
+my-age: 30
+
+my-age-test: 40
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/application.yml b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/application.yml
new file mode 100644
index 000000000..3404bf51c
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/application.yml
@@ -0,0 +1,20 @@
+spring:
+ datasource:
+ driver-class-name: org.h2.Driver
+ url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=1
+ username: sa
+ password:
+
+ jpa:
+ hibernate:
+ ddl-auto: update
+ show-sql: true
+
+server:
+ port: 8081
+
+my-name: frank
+my-age: 35
+REMOTE_BASE_URI: http://localhost:8080
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_account.json b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_account.json
new file mode 100644
index 000000000..c8361b6aa
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_account.json
@@ -0,0 +1,30 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/api/account/[0-9]+",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "transformers": [
+ "response-template"
+ ],
+ "jsonBody": {
+ "name": "frank",
+ "phoneNo": "{{request.path.[3]}}",
+ "remaining": "400",
+ "chargePlanList": [
+ {
+ "priority": "2",
+ "type": "fixedTime"
+ },
+ {
+ "priority": "1",
+ "type": "familyMember"
+ }
+ ]
+ }
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_insufficient_account.json b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_insufficient_account.json
new file mode 100644
index 000000000..a0f3c8b8c
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_insufficient_account.json
@@ -0,0 +1,30 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/api/account/[0-9]+",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "transformers": [
+ "response-template"
+ ],
+ "jsonBody": {
+ "name": "frank",
+ "phoneNo": "{{request.path.[3]}}",
+ "remaining": "0",
+ "chargePlanList": [
+ {
+ "priority": "2",
+ "type": "fixedTime"
+ },
+ {
+ "priority": "1",
+ "type": "familyMember"
+ }
+ ]
+ }
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_wire_mock_basic.json b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_wire_mock_basic.json
new file mode 100644
index 000000000..bbe019de4
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/fixture/wiremock/stub_wire_mock_basic.json
@@ -0,0 +1,30 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/wiremock/basic",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "jsonBody": {
+ "request_id": "f7f9e747-f073-4ea8-8360-b42fc754a049",
+ "hyper_switch": {
+ "id": "switch1",
+ "name": "1520-001",
+ "device_model": "1520",
+ "role": "tor",
+ "mgmt_ip": "192.168.0.1",
+ "rack_code": "kw14b2-1k-01-08",
+ "sn": "21980119523GP8000745",
+ "node_id": "node1",
+ "xpod_id": "pod1",
+ "op_status": "online",
+ "created_at": "2024-02-04 15:11:13",
+ "updated_at": "2020-02-04 15:11:13",
+ "type": "l1"
+ }
+ }
+ }
+}
diff --git a/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/logback-test.xml b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/logback-test.xml
new file mode 100644
index 000000000..042cf5664
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/main/resources/archetype-resources/src/test/resources/logback-test.xml
@@ -0,0 +1,29 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+
+
+
+
+
+ %date{HH:mm:ss} %highlight(%-5level) [%blue(%t)] %yellow(%C{35}): %msg%n%throwable
+ utf8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cola-archetypes/cola-archetype-light/src/test/resources/projects/basic/archetype.properties b/cola-archetypes/cola-archetype-light/src/test/resources/projects/basic/archetype.properties
new file mode 100644
index 000000000..61f690016
--- /dev/null
+++ b/cola-archetypes/cola-archetype-light/src/test/resources/projects/basic/archetype.properties
@@ -0,0 +1,5 @@
+#Sun May 12 20:30:31 CST 2024
+package=it.pkg
+groupId=archetype.it
+artifactId=basic
+version=0.1-SNAPSHOT
diff --git a/cola-archetypes/cola-archetype-light/src/test/resources/projects/basic/goal.txt b/cola-archetypes/cola-archetype-light/src/test/resources/projects/basic/goal.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/cola-components/cola-component-catchlog-starter/pom.xml b/cola-components/cola-component-catchlog-starter/pom.xml
index 5fb3ff660..3dbdeef34 100644
--- a/cola-components/cola-component-catchlog-starter/pom.xml
+++ b/cola-components/cola-component-catchlog-starter/pom.xml
@@ -77,11 +77,6 @@
provided
-
-
- org.slf4j
- slf4j-api
-
diff --git a/cola-components/cola-component-catchlog-starter/src/test/java/com/alibaba/cola/catchlog/test/CatchLogTest.java b/cola-components/cola-component-catchlog-starter/src/test/java/com/alibaba/cola/catchlog/test/CatchLogTest.java
index 583f881a8..c745fc6bd 100644
--- a/cola-components/cola-component-catchlog-starter/src/test/java/com/alibaba/cola/catchlog/test/CatchLogTest.java
+++ b/cola-components/cola-component-catchlog-starter/src/test/java/com/alibaba/cola/catchlog/test/CatchLogTest.java
@@ -2,17 +2,13 @@
import com.alibaba.cola.catchlog.CatchLogAspect;
import com.alibaba.cola.catchlog.CatchLogAutoConfiguration;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
-import javax.annotation.Resource;
/**
*
*/
-@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {CatchLogAutoConfiguration.class, Demo.class, CatchLogAspect.class, Application.class})
public class CatchLogTest {
diff --git a/cola-components/cola-component-domain-starter/src/test/java/com/alibaba/cola/domain/Customer.java b/cola-components/cola-component-domain-starter/src/test/java/com/alibaba/cola/domain/Customer.java
index 7ab16498a..5b880e190 100644
--- a/cola-components/cola-component-domain-starter/src/test/java/com/alibaba/cola/domain/Customer.java
+++ b/cola-components/cola-component-domain-starter/src/test/java/com/alibaba/cola/domain/Customer.java
@@ -1,8 +1,8 @@
package com.alibaba.cola.domain;
import com.alibaba.cola.domain.Entity;
+import jakarta.annotation.Resource;
-import javax.annotation.Resource;
/**
* Customer
diff --git a/cola-components/cola-component-extension-starter/README.md b/cola-components/cola-component-extension-starter/README.md
index 23229e121..beb2398cf 100644
--- a/cola-components/cola-component-extension-starter/README.md
+++ b/cola-components/cola-component-extension-starter/README.md
@@ -5,5 +5,5 @@
https://blog.csdn.net/significantfrank/article/details/100074716
## 使用介绍
-参看测试代码`com.alibaba.cola.extension.test.ExtensionTest`
+参看测试代码`com.alibaba.cola.extension.ExtensionTest`
diff --git a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extension.java b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extension.java
index fcd63efb8..1e446967b 100644
--- a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extension.java
+++ b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extension.java
@@ -18,7 +18,6 @@
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
-@Repeatable(Extensions.class)
@Component
public @interface Extension {
String bizId() default BizScenario.DEFAULT_BIZ_ID;
diff --git a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/ExtensionExecutor.java b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/ExtensionExecutor.java
index 17ad7f442..09c14cd26 100644
--- a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/ExtensionExecutor.java
+++ b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/ExtensionExecutor.java
@@ -8,11 +8,11 @@
package com.alibaba.cola.extension;
import com.alibaba.cola.extension.register.AbstractComponentExecutor;
+import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
-import javax.annotation.Resource;
/**
* ExtensionExecutor
diff --git a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extensions.java b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extensions.java
index fed45ffb0..cdd28b131 100644
--- a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extensions.java
+++ b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/Extensions.java
@@ -24,6 +24,4 @@
String[] scenario() default BizScenario.DEFAULT_SCENARIO;
- Extension[] value() default {};
-
}
diff --git a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionBootstrap.java b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionBootstrap.java
index 56735ceae..cb30f9f75 100644
--- a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionBootstrap.java
+++ b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionBootstrap.java
@@ -3,14 +3,15 @@
import com.alibaba.cola.extension.Extension;
import com.alibaba.cola.extension.ExtensionPointI;
import com.alibaba.cola.extension.Extensions;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
-import javax.annotation.PostConstruct;
-import javax.annotation.Resource;
+
import java.util.Map;
/**
diff --git a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionRegister.java b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionRegister.java
index d29dc02e0..4fa4e566e 100644
--- a/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionRegister.java
+++ b/cola-components/cola-component-extension-starter/src/main/java/com/alibaba/cola/extension/register/ExtensionRegister.java
@@ -8,6 +8,7 @@
package com.alibaba.cola.extension.register;
import com.alibaba.cola.extension.*;
+import jakarta.annotation.Resource;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
@@ -15,8 +16,6 @@
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
-import javax.annotation.Resource;
-
/**
* ExtensionRegister
*
@@ -66,20 +65,8 @@ public void doRegistrationExtensions(ExtensionPointI extensionObject){
}
Extensions extensionsAnnotation = AnnotationUtils.findAnnotation(extensionClz, Extensions.class);
- Extension[] extensions = extensionsAnnotation.value();
- if (!ObjectUtils.isEmpty(extensions)){
- for (Extension extensionAnn : extensions) {
- BizScenario bizScenario = BizScenario.valueOf(extensionAnn.bizId(), extensionAnn.useCase(), extensionAnn.scenario());
- ExtensionCoordinate extensionCoordinate = new ExtensionCoordinate(calculateExtensionPoint(extensionClz), bizScenario.getUniqueIdentity());
- ExtensionPointI preVal = extensionRepository.getExtensionRepo().put(extensionCoordinate, extensionObject);
- if (preVal != null) {
- String errMessage = "Duplicate registration is not allowed for :" + extensionCoordinate;
- throw new ExtensionException(EXTENSION_DEFINE_DUPLICATE, errMessage);
- }
- }
- }
- //
+ //Support multiple extensions registration
String[] bizIds = extensionsAnnotation.bizId();
String[] useCases = extensionsAnnotation.useCase();
String[] scenarios = extensionsAnnotation.scenario();
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/Application.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/Application.java
new file mode 100644
index 000000000..c0fe7300b
--- /dev/null
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/Application.java
@@ -0,0 +1,20 @@
+package com.alibaba.cola.extension;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * Application
+ *
+ * @author Frank Zhang
+ * @date 2020-11-10 3:58 PM
+ */
+@SpringBootApplication
+@ComponentScan(basePackages = "com.alibaba.cola")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/ExtensionTest.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/ExtensionTest.java
similarity index 74%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/ExtensionTest.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/ExtensionTest.java
index d3f16d0f7..492455232 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/ExtensionTest.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/ExtensionTest.java
@@ -1,19 +1,18 @@
-package com.alibaba.cola.extension.test;
+package com.alibaba.cola.extension;
import com.alibaba.cola.dto.Response;
-import com.alibaba.cola.extension.BizScenario;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.client.CustomerDTO;
-import com.alibaba.cola.extension.test.customer.client.CustomerServiceI;
-import com.alibaba.cola.extension.test.customer.domain.CustomerType;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.client.CustomerDTO;
+import com.alibaba.cola.extension.customer.client.CustomerServiceI;
+import com.alibaba.cola.extension.customer.domain.CustomerType;
+import jakarta.annotation.Resource;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import javax.annotation.Resource;
+
/**
* ExtensionTest
@@ -21,7 +20,6 @@
* @author Frank Zhang
* @date 2020-11-14 2:55 PM
*/
-@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ExtensionTest {
@Resource
@@ -43,7 +41,7 @@ public void testBiz1UseCase1Scenario1AddCustomerSuccess(){
Response response = customerService.addCustomer(addCustomerCmd);
//3. Expect Success
- Assert.assertTrue(response.isSuccess());
+ Assertions.assertTrue(response.isSuccess());
}
@Test
@@ -62,7 +60,7 @@ public void testBiz1UseCase1AddCustomerSuccess(){
Response response = customerService.addCustomer(addCustomerCmd);
//3. Expect Success
- Assert.assertTrue(response.isSuccess());
+ Assertions.assertTrue(response.isSuccess());
}
@Test
@@ -81,6 +79,6 @@ public void testBiz1AddCustomerSuccess(){
Response response = customerService.addCustomer(addCustomerCmd);
//3. Expect Success
- Assert.assertTrue(response.isSuccess());
+ Assertions.assertTrue(response.isSuccess());
}
}
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/MultiCoordinateTests.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/MultiCoordinateTests.java
similarity index 60%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/MultiCoordinateTests.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/MultiCoordinateTests.java
index ff6119f7c..1d56027dc 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/MultiCoordinateTests.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/MultiCoordinateTests.java
@@ -1,15 +1,12 @@
-package com.alibaba.cola.extension.test;
+package com.alibaba.cola.extension;
-import com.alibaba.cola.extension.BizScenario;
-import com.alibaba.cola.extension.ExtensionExecutor;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.StatusNameConvertorExtPt;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import com.alibaba.cola.extension.customer.app.extensionpoint.StatusNameConvertorExtPt;
+
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import javax.annotation.Resource;
/**
* 多坐标测试
@@ -17,7 +14,6 @@
* @author wangguoqiang wrote on 2022/10/10 14:54
* @version 1.0
*/
-@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class MultiCoordinateTests {
@@ -45,23 +41,13 @@ public void testMultiCoordinate() {
String name7 = extensionExecutor.execute(StatusNameConvertorExtPt.class, bizScenario7, pt -> pt.statusNameConvertor(7));
String name8 = extensionExecutor.execute(StatusNameConvertorExtPt.class, bizScenario8, pt -> pt.statusNameConvertor(8));
- Assert.assertEquals("one",name1);
- Assert.assertEquals("two",name2);
- Assert.assertEquals("three",name3);
- Assert.assertEquals("four",name4);
- Assert.assertEquals("five",name5);
- Assert.assertEquals("six",name6);
- Assert.assertEquals("seven",name7);
- Assert.assertEquals("eight",name8);
- }
-
- @Test
- public void testMultiCoordinateWithAnnotation() {
- BizScenario bizScenario1 = BizScenario.valueOf("Sony", "user", "scenario3");
- BizScenario bizScenario2 = BizScenario.valueOf("Siemens", "order", "scenario1");
- String name1 = extensionExecutor.execute(StatusNameConvertorExtPt.class, bizScenario1, pt -> pt.statusNameConvertor(1));
- String name2 = extensionExecutor.execute(StatusNameConvertorExtPt.class, bizScenario2, pt -> pt.statusNameConvertor(2));
- Assert.assertEquals("one",name1);
- Assert.assertEquals("two",name2);
+ Assertions.assertEquals("one",name1);
+ Assertions.assertEquals("two",name2);
+ Assertions.assertEquals("three",name3);
+ Assertions.assertEquals("four",name4);
+ Assertions.assertEquals("five",name5);
+ Assertions.assertEquals("six",name6);
+ Assertions.assertEquals("seven",name7);
+ Assertions.assertEquals("eight",name8);
}
}
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/AddCustomerCmdExe.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/AddCustomerCmdExe.java
similarity index 72%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/AddCustomerCmdExe.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/AddCustomerCmdExe.java
index 86bdaa0e8..03b84b54a 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/AddCustomerCmdExe.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/AddCustomerCmdExe.java
@@ -1,18 +1,17 @@
-package com.alibaba.cola.extension.test.customer.app;
+package com.alibaba.cola.extension.customer.app;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.extension.ExtensionExecutor;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.CustomerConvertorExtPt;
-import com.alibaba.cola.extension.test.customer.infrastructure.DomainEventPublisher;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.AddCustomerValidatorExtPt;
+import com.alibaba.cola.extension.customer.app.extensionpoint.AddCustomerValidatorExtPt;
+import com.alibaba.cola.extension.customer.app.extensionpoint.CustomerConvertorExtPt;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.infrastructure.DomainEventPublisher;
+import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
-import javax.annotation.Resource;
-
/**
* AddCustomerCmdExe
*
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/CustomerCreatedEventHandler.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/CustomerCreatedEventHandler.java
similarity index 72%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/CustomerCreatedEventHandler.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/CustomerCreatedEventHandler.java
index 4e134c5cc..131e021ca 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/CustomerCreatedEventHandler.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/CustomerCreatedEventHandler.java
@@ -1,7 +1,7 @@
-package com.alibaba.cola.extension.test.customer.app;
+package com.alibaba.cola.extension.customer.app;
import com.alibaba.cola.dto.Response;
-import com.alibaba.cola.extension.test.customer.client.CustomerCreatedEvent;
+import com.alibaba.cola.extension.customer.client.CustomerCreatedEvent;
/**
* CustomerCreatedEventHandler
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/CustomerServiceImpl.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/CustomerServiceImpl.java
similarity index 66%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/CustomerServiceImpl.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/CustomerServiceImpl.java
index a621460da..c2dd6fce5 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/CustomerServiceImpl.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/CustomerServiceImpl.java
@@ -1,15 +1,14 @@
-package com.alibaba.cola.extension.test.customer.app;
+package com.alibaba.cola.extension.customer.app;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.CustomerDTO;
-import com.alibaba.cola.extension.test.customer.client.CustomerServiceI;
-import com.alibaba.cola.extension.test.customer.client.GetOneCustomerQry;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.CustomerDTO;
+import com.alibaba.cola.extension.customer.client.CustomerServiceI;
+import com.alibaba.cola.extension.customer.client.GetOneCustomerQry;
+import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
-import javax.annotation.Resource;
-
/**
* CustomerServiceImpl
*
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/GetOneCustomerQryExe.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/GetOneCustomerQryExe.java
similarity index 72%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/GetOneCustomerQryExe.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/GetOneCustomerQryExe.java
index 8704bc56c..7b6d5b241 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/GetOneCustomerQryExe.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/GetOneCustomerQryExe.java
@@ -1,7 +1,7 @@
-package com.alibaba.cola.extension.test.customer.app;
+package com.alibaba.cola.extension.customer.app;
import com.alibaba.cola.dto.SingleResponse;
-import com.alibaba.cola.extension.test.customer.client.GetOneCustomerQry;
+import com.alibaba.cola.extension.customer.client.GetOneCustomerQry;
import org.springframework.stereotype.Component;
/**
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBiz1UseCase1Scenario1Validator.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBiz1UseCase1Scenario1Validator.java
similarity index 63%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBiz1UseCase1Scenario1Validator.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBiz1UseCase1Scenario1Validator.java
index 9227071fa..7baf459a4 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBiz1UseCase1Scenario1Validator.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBiz1UseCase1Scenario1Validator.java
@@ -1,9 +1,9 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.AddCustomerValidatorExtPt;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.app.extensionpoint.AddCustomerValidatorExtPt;
/**
* AddCustomerBiz1UseCase1Scenario1Validator
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBiz1UseCase1Validator.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBiz1UseCase1Validator.java
similarity index 59%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBiz1UseCase1Validator.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBiz1UseCase1Validator.java
index 9ef14636f..a78711049 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBiz1UseCase1Validator.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBiz1UseCase1Validator.java
@@ -1,9 +1,9 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.AddCustomerValidatorExtPt;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.app.extensionpoint.AddCustomerValidatorExtPt;
/**
* AddCustomerBiz1UseCase1Validator
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBizOneValidator.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBizOneValidator.java
similarity index 61%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBizOneValidator.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBizOneValidator.java
index 6cdae6159..2f51b12f7 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBizOneValidator.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBizOneValidator.java
@@ -1,11 +1,11 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
import com.alibaba.cola.exception.BizException;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.domain.CustomerType;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.AddCustomerValidatorExtPt;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.domain.CustomerType;
+import com.alibaba.cola.extension.customer.app.extensionpoint.AddCustomerValidatorExtPt;
/**
* AddCustomerBizOneValidator
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBizTwoValidator.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBizTwoValidator.java
similarity index 65%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBizTwoValidator.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBizTwoValidator.java
index 4cb10872c..9de4d2da8 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/AddCustomerBizTwoValidator.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/AddCustomerBizTwoValidator.java
@@ -1,10 +1,10 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
import com.alibaba.cola.exception.BizException;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.AddCustomerValidatorExtPt;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.app.extensionpoint.AddCustomerValidatorExtPt;
/**
* AddCustomerBizTwoValidator
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerBizOneConvertorExt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerBizOneConvertorExt.java
similarity index 68%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerBizOneConvertorExt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerBizOneConvertorExt.java
index 6c69c9fbb..4f3a464c7 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerBizOneConvertorExt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerBizOneConvertorExt.java
@@ -1,12 +1,12 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.CustomerConvertorExtPt;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.client.CustomerDTO;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
-import com.alibaba.cola.extension.test.customer.domain.SourceType;
+import com.alibaba.cola.extension.customer.app.extensionpoint.CustomerConvertorExtPt;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.client.CustomerDTO;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.domain.SourceType;
import org.springframework.beans.factory.annotation.Autowired;
/**
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerBizTwoConvertorExt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerBizTwoConvertorExt.java
similarity index 69%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerBizTwoConvertorExt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerBizTwoConvertorExt.java
index ad5b05bca..c877ee4c6 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerBizTwoConvertorExt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerBizTwoConvertorExt.java
@@ -1,11 +1,11 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.CustomerConvertorExtPt;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
-import com.alibaba.cola.extension.test.customer.domain.SourceType;
+import com.alibaba.cola.extension.customer.app.extensionpoint.CustomerConvertorExtPt;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.domain.SourceType;
import org.springframework.beans.factory.annotation.Autowired;
/**
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerConvertor.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerConvertor.java
similarity index 74%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerConvertor.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerConvertor.java
index 2962e7ddc..a6b30594f 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/CustomerConvertor.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/CustomerConvertor.java
@@ -1,9 +1,9 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
import com.alibaba.cola.domain.ApplicationContextHelper;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.client.CustomerDTO;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.CustomerDTO;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
import org.springframework.stereotype.Component;
/**
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/StatusNameConvertorExt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/StatusNameConvertorExt.java
similarity index 67%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/StatusNameConvertorExt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/StatusNameConvertorExt.java
index c36861eda..4e844b5bb 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extension/StatusNameConvertorExt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extension/StatusNameConvertorExt.java
@@ -1,8 +1,7 @@
-package com.alibaba.cola.extension.test.customer.app.extension;
+package com.alibaba.cola.extension.customer.app.extension;
-import com.alibaba.cola.extension.Extension;
import com.alibaba.cola.extension.Extensions;
-import com.alibaba.cola.extension.test.customer.app.extensionpoint.StatusNameConvertorExtPt;
+import com.alibaba.cola.extension.customer.app.extensionpoint.StatusNameConvertorExtPt;
import java.util.HashMap;
@@ -10,12 +9,7 @@
* @author wangguoqiang wrote on 2022/10/10 14:39
* @version 1.0
*/
-@Extensions(bizId = {"Samsung", "Motorola"}, useCase = {"order", "parts"}, scenario = {"scenario1", "scenario2"},
- value = {
- @Extension(bizId = "Sony", useCase = "user", scenario = "scenario3"),
- @Extension(bizId = "Siemens", useCase = "order", scenario = "scenario1")
- }
-)
+@Extensions(bizId = {"Samsung", "Motorola"}, useCase = {"order", "parts"}, scenario = {"scenario1", "scenario2"})
public class StatusNameConvertorExt implements StatusNameConvertorExtPt {
/**
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/AddCustomerValidatorExtPt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/AddCustomerValidatorExtPt.java
similarity index 66%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/AddCustomerValidatorExtPt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/AddCustomerValidatorExtPt.java
index addc6cc13..c5fc75b23 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/AddCustomerValidatorExtPt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/AddCustomerValidatorExtPt.java
@@ -1,7 +1,7 @@
-package com.alibaba.cola.extension.test.customer.app.extensionpoint;
+package com.alibaba.cola.extension.customer.app.extensionpoint;
import com.alibaba.cola.extension.ExtensionPointI;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
/**
* AddCustomerValidatorExtPt
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/CustomerConvertorExtPt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/CustomerConvertorExtPt.java
similarity index 57%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/CustomerConvertorExtPt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/CustomerConvertorExtPt.java
index c094cc449..603dad743 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/CustomerConvertorExtPt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/CustomerConvertorExtPt.java
@@ -1,8 +1,8 @@
-package com.alibaba.cola.extension.test.customer.app.extensionpoint;
+package com.alibaba.cola.extension.customer.app.extensionpoint;
import com.alibaba.cola.extension.ExtensionPointI;
-import com.alibaba.cola.extension.test.customer.client.AddCustomerCmd;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.client.AddCustomerCmd;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
/**
* CustomerConvertorExtPt
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/StatusNameConvertorExtPt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/StatusNameConvertorExtPt.java
similarity index 84%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/StatusNameConvertorExtPt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/StatusNameConvertorExtPt.java
index bdb392016..2586fda6d 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/app/extensionpoint/StatusNameConvertorExtPt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/app/extensionpoint/StatusNameConvertorExtPt.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.app.extensionpoint;
+package com.alibaba.cola.extension.customer.app.extensionpoint;
import com.alibaba.cola.extension.ExtensionPointI;
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/AddCustomerCmd.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/AddCustomerCmd.java
similarity index 85%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/AddCustomerCmd.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/AddCustomerCmd.java
index d772b027f..8839a75e3 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/AddCustomerCmd.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/AddCustomerCmd.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.client;
+package com.alibaba.cola.extension.customer.client;
import com.alibaba.cola.dto.Command;
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/Constants.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/Constants.java
similarity index 91%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/Constants.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/Constants.java
index 5f98e3d75..2e1dbe39a 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/Constants.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/Constants.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.client;
+package com.alibaba.cola.extension.customer.client;
/**
* Constants
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerCreatedEvent.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerCreatedEvent.java
similarity index 68%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerCreatedEvent.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerCreatedEvent.java
index 585594c61..066ba540c 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerCreatedEvent.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerCreatedEvent.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.client;
+package com.alibaba.cola.extension.customer.client;
/**
* CustomerCreatedEvent
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerDTO.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerDTO.java
similarity index 86%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerDTO.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerDTO.java
index c13e32766..9f000df02 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerDTO.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerDTO.java
@@ -1,7 +1,7 @@
-package com.alibaba.cola.extension.test.customer.client;
+package com.alibaba.cola.extension.customer.client;
import com.alibaba.cola.dto.DTO;
-import com.alibaba.cola.extension.test.customer.domain.CustomerType;
+import com.alibaba.cola.extension.customer.domain.CustomerType;
/**
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerServiceI.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerServiceI.java
similarity index 85%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerServiceI.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerServiceI.java
index 2f8165e99..c9cb21137 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/CustomerServiceI.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/CustomerServiceI.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.client;
+package com.alibaba.cola.extension.customer.client;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/GetOneCustomerQry.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/GetOneCustomerQry.java
similarity index 90%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/GetOneCustomerQry.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/GetOneCustomerQry.java
index 615142f7d..2aaba907b 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/client/GetOneCustomerQry.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/client/GetOneCustomerQry.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.client;
+package com.alibaba.cola.extension.customer.client;
import com.alibaba.cola.dto.Query;
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/CustomerEntity.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/CustomerEntity.java
similarity index 87%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/CustomerEntity.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/CustomerEntity.java
index e434f6a7e..2da8dfec1 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/CustomerEntity.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/CustomerEntity.java
@@ -1,10 +1,10 @@
-package com.alibaba.cola.extension.test.customer.domain;
+package com.alibaba.cola.extension.customer.domain;
import com.alibaba.cola.domain.Entity;
import com.alibaba.cola.extension.BizScenario;
import com.alibaba.cola.extension.ExtensionExecutor;
-import com.alibaba.cola.extension.test.customer.domain.rule.CustomerRuleExtPt;
-import com.alibaba.cola.extension.test.customer.infrastructure.CustomerRepository;
+import com.alibaba.cola.extension.customer.domain.rule.CustomerRuleExtPt;
+import com.alibaba.cola.extension.customer.infrastructure.CustomerRepository;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/CustomerType.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/CustomerType.java
similarity index 73%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/CustomerType.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/CustomerType.java
index ff8175762..a41f69d88 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/CustomerType.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/CustomerType.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.domain;
+package com.alibaba.cola.extension.customer.domain;
/**
* CustomerType
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/SourceType.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/SourceType.java
similarity index 77%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/SourceType.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/SourceType.java
index 9a38f2d38..c7f584c8e 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/SourceType.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/SourceType.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.domain;
+package com.alibaba.cola.extension.customer.domain;
/**
* SourceType
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerBizOneRuleExt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerBizOneRuleExt.java
similarity index 68%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerBizOneRuleExt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerBizOneRuleExt.java
index 87ed3adf7..e2a3c3dc9 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerBizOneRuleExt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerBizOneRuleExt.java
@@ -1,10 +1,10 @@
-package com.alibaba.cola.extension.test.customer.domain.rule;
+package com.alibaba.cola.extension.customer.domain.rule;
import com.alibaba.cola.exception.BizException;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
-import com.alibaba.cola.extension.test.customer.domain.SourceType;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.domain.SourceType;
/**
* CustomerBizOneRuleExt
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerBizTwoRuleExt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerBizTwoRuleExt.java
similarity index 66%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerBizTwoRuleExt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerBizTwoRuleExt.java
index a98bffe70..a072627f1 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerBizTwoRuleExt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerBizTwoRuleExt.java
@@ -1,8 +1,8 @@
-package com.alibaba.cola.extension.test.customer.domain.rule;
+package com.alibaba.cola.extension.customer.domain.rule;
import com.alibaba.cola.extension.Extension;
-import com.alibaba.cola.extension.test.customer.client.Constants;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.client.Constants;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
/**
* CustomerBizTwoRuleExt
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerRuleExtPt.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerRuleExtPt.java
similarity index 78%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerRuleExtPt.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerRuleExtPt.java
index 2eb1efda6..07bb14470 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/domain/rule/CustomerRuleExtPt.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/domain/rule/CustomerRuleExtPt.java
@@ -1,7 +1,7 @@
-package com.alibaba.cola.extension.test.customer.domain.rule;
+package com.alibaba.cola.extension.customer.domain.rule;
import com.alibaba.cola.extension.ExtensionPointI;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
/**
* CustomerRuleExtPt
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/CustomerDO.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/CustomerDO.java
similarity index 95%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/CustomerDO.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/CustomerDO.java
index 5d3b205d5..8828a6b3b 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/CustomerDO.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/CustomerDO.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.infrastructure;
+package com.alibaba.cola.extension.customer.infrastructure;
/**
* CustomerDO
@@ -62,4 +62,4 @@ public String getCompanyType() {
public void setCompanyType(String companyType) {
this.companyType = companyType;
}
-}
\ No newline at end of file
+}
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/CustomerRepository.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/CustomerRepository.java
similarity index 70%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/CustomerRepository.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/CustomerRepository.java
index 8f1c4d8b0..28bfc4d24 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/CustomerRepository.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/CustomerRepository.java
@@ -1,6 +1,6 @@
-package com.alibaba.cola.extension.test.customer.infrastructure;
+package com.alibaba.cola.extension.customer.infrastructure;
-import com.alibaba.cola.extension.test.customer.domain.CustomerEntity;
+import com.alibaba.cola.extension.customer.domain.CustomerEntity;
import org.springframework.stereotype.Repository;
/**
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/DomainEventPublisher.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/DomainEventPublisher.java
similarity index 83%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/DomainEventPublisher.java
rename to cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/DomainEventPublisher.java
index bb42f00d9..02e562c61 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/customer/infrastructure/DomainEventPublisher.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/customer/infrastructure/DomainEventPublisher.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test.customer.infrastructure;
+package com.alibaba.cola.extension.customer.infrastructure;
import org.springframework.stereotype.Component;
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/register/ExtensionRegisterTest.java b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/register/ExtensionRegisterTest.java
index f671160b6..8ddf72539 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/register/ExtensionRegisterTest.java
+++ b/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/register/ExtensionRegisterTest.java
@@ -1,20 +1,17 @@
package com.alibaba.cola.extension.register;
-import javax.annotation.Resource;
-
import com.alibaba.cola.extension.BizScenario;
+import com.alibaba.cola.extension.ExtensionException;
import com.alibaba.cola.extension.ExtensionExecutor;
-import com.alibaba.cola.extension.test.Application;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import com.alibaba.cola.extension.Application;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ExtensionRegisterTest {
-
+
@Resource
private ExtensionRegister register;
@@ -22,15 +19,16 @@ public class ExtensionRegisterTest {
private ExtensionExecutor executor;
@Test
- public void test() {
- SomeExtPt extA = new SomeExtensionA();
- register.doRegistration(extA);
+ public void testDuplicateRegistration() {
+ // expect:
+ //Duplicate registration is not allowed for :ExtensionCoordinate
+ // [extensionPointName=com.alibaba.cola.extension.register.SomeExtPt, bizScenarioUniqueIdentity=A.#defaultUseCase#.#defaultScenario#]
+ Assertions.assertThrows(ExtensionException.class, ()->{
+ SomeExtPt extA = new SomeExtensionA();
+ register.doRegistration(extA);
- SomeExtPt extB = CglibProxyFactory.createProxy(new SomeExtensionB());
- register.doRegistration(extB);
-
- executor.executeVoid(SomeExtPt.class, BizScenario.valueOf("A"), SomeExtPt::doSomeThing);
- executor.executeVoid(SomeExtPt.class, BizScenario.valueOf("B"), SomeExtPt::doSomeThing);
+ executor.executeVoid(SomeExtPt.class, BizScenario.valueOf("A"), SomeExtPt::doSomeThing);
+ });
}
-
+
}
diff --git a/cola-components/cola-component-ruleengine/pom.xml b/cola-components/cola-component-ruleengine/pom.xml
index ff0028faf..5c11f8ed6 100644
--- a/cola-components/cola-component-ruleengine/pom.xml
+++ b/cola-components/cola-component-ruleengine/pom.xml
@@ -66,20 +66,5 @@
slf4j-simple
test
-
- junit
- junit
- test
-
-
- org.assertj
- assertj-core
- test
-
-
- org.mockito
- mockito-core
- test
-
diff --git a/cola-components/cola-component-ruleengine/src/main/java/com/alibaba/cola/ruleengine/api/Facts.java b/cola-components/cola-component-ruleengine/src/main/java/com/alibaba/cola/ruleengine/api/Facts.java
index 68b089554..8109ad91c 100644
--- a/cola-components/cola-component-ruleengine/src/main/java/com/alibaba/cola/ruleengine/api/Facts.java
+++ b/cola-components/cola-component-ruleengine/src/main/java/com/alibaba/cola/ruleengine/api/Facts.java
@@ -92,6 +92,21 @@ public Fact> getFact(String factName) {
.orElse(null);
}
+ public boolean contains(String factName){
+ return getFact(factName) != null;
+ }
+
+ public boolean contains(Fact fact){
+ if(fact == null){
+ return false;
+ }
+ return getFact(fact.getName()) != null;
+ }
+
+ public int size(){
+ return facts.size();
+ }
+
/**
* Return a copy of the facts as a map. It is not intended to manipulate
* facts outside of the rules engine (aka other than manipulating them through rules).
diff --git a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/CompositeRuleTest.java b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/CompositeRuleTest.java
index e9631c54c..94360872d 100644
--- a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/CompositeRuleTest.java
+++ b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/CompositeRuleTest.java
@@ -4,20 +4,21 @@
import com.alibaba.cola.ruleengine.api.Rule;
import com.alibaba.cola.ruleengine.api.RuleEngine;
import com.alibaba.cola.ruleengine.core.*;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
public class CompositeRuleTest {
RuleEngine fizzBuzzEngine;
- @Before
+ @BeforeEach
public void setUp(){
fizzBuzzEngine = new DefaultRuleEngine();
}
+
+
@Test
public void test_fizz_first(){
Facts facts = new Facts();
@@ -26,7 +27,7 @@ public void test_fizz_first(){
Rule rule = assembleRules(1,2,3);
fizzBuzzEngine.fire(rule, facts);
- assertThat(facts.getFact("fizz").getValue()).isEqualTo("Fizz");
+ assertEquals(facts.getFact("fizz").getValue(), "Fizz");
}
@Test
@@ -37,7 +38,7 @@ public void test_buzz_first(){
Rule rule = assembleRules(2,1,3);
fizzBuzzEngine.fire(rule, facts);
- assertThat(facts.getFact("buzz").getValue()).isEqualTo("Buzz");
+ assertEquals(facts.getFact("buzz").getValue(), "Buzz");
}
@Test
@@ -48,8 +49,8 @@ public void test_fizzBuzz_first(){
Rule rule = assembleRules(2,3,1);
fizzBuzzEngine.fire(rule, facts);
- assertThat(facts.getFact("fizz").getValue()).isEqualTo("Fizz");
- assertThat(facts.getFact("buzz").getValue()).isEqualTo("Buzz");
+ assertEquals(facts.getFact("fizz").getValue(), "Fizz");
+ assertEquals(facts.getFact("buzz").getValue(), "Buzz");
}
diff --git a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/FactsTest.java b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/FactsTest.java
index 751f4a4c2..ac4889251 100644
--- a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/FactsTest.java
+++ b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/FactsTest.java
@@ -2,12 +2,10 @@
import com.alibaba.cola.ruleengine.api.Fact;
import com.alibaba.cola.ruleengine.api.Facts;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
import java.util.Map;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
public class FactsTest {
@@ -18,9 +16,9 @@ public void factsMustHaveUniqueName() {
facts.add(new Fact<>("foo", 1));
facts.add(new Fact<>("foo", 2));
- assertThat(facts).hasSize(1);
+
Fact> fact = facts.getFact("foo");
- assertThat(fact.getValue()).isEqualTo(2);
+ assertEquals(fact.getValue(),2);
}
@Test
@@ -30,8 +28,8 @@ public void testAdd() {
facts.add(fact1);
facts.add(fact2);
- assertThat(facts).contains(fact1);
- assertThat(facts).contains(fact2);
+ assertTrue(facts.contains(fact1));
+ assertTrue(facts.contains(fact2));
}
@Test
@@ -39,8 +37,8 @@ public void testPut() {
facts.put("foo", 1);
facts.put("bar", 2);
- assertThat(facts).contains(new Fact<>("foo", 1));
- assertThat(facts).contains(new Fact<>("bar", 2));
+ assertTrue(facts.contains(new Fact<>("foo", 1)));
+ assertTrue(facts.contains(new Fact<>("bar", 2)));
}
@Test
@@ -49,7 +47,7 @@ public void testRemove() {
facts.add(foo);
facts.remove(foo);
- assertThat(facts).isEmpty();
+ assertTrue(facts.size() == 0);
}
@Test
@@ -58,7 +56,7 @@ public void testRemoveByName() {
facts.add(foo);
facts.remove("foo");
- assertThat(facts).isEmpty();
+ assertTrue(facts.size() == 0);
}
@Test
@@ -66,7 +64,7 @@ public void testGet() {
Fact fact = new Fact<>("foo", 1);
facts.add(fact);
Integer value = facts.get("foo");
- assertThat(value).isEqualTo(1);
+ assertEquals(value, 1);
}
@Test
@@ -74,7 +72,7 @@ public void testGetFact() {
Fact fact = new Fact<>("foo", 1);
facts.add(fact);
Fact> retrievedFact = facts.getFact("foo");
- assertThat(retrievedFact).isEqualTo(fact);
+ assertEquals(retrievedFact, fact);
}
@Test
@@ -84,8 +82,8 @@ public void testAsMap() {
facts.add(fact1);
facts.add(fact2);
Map map = facts.asMap();
- assertThat(map).containsKeys("foo", "bar");
- assertThat(map).containsValues(1, 2);
+ assertTrue(map.containsKey("foo"));
+ assertTrue(map.containsKey("bar"));
}
@Test
@@ -93,7 +91,8 @@ public void testClear() {
Facts facts = new Facts();
facts.add(new Fact<>("foo", 1));
facts.clear();
- assertThat(facts).isEmpty();
+
+ assertTrue(facts.size() == 0);
}
}
diff --git a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/PriorityTest.java b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/PriorityTest.java
index 4f6c8790f..b93ed7b56 100644
--- a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/PriorityTest.java
+++ b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/PriorityTest.java
@@ -2,58 +2,76 @@
import com.alibaba.cola.ruleengine.api.Facts;
import com.alibaba.cola.ruleengine.api.Rule;
-import com.alibaba.cola.ruleengine.core.AbstractRule;
-import org.junit.Test;
+import com.alibaba.cola.ruleengine.api.RuleEngine;
+import com.alibaba.cola.ruleengine.core.DefaultRule;
+import com.alibaba.cola.ruleengine.core.DefaultRuleEngine;
+import com.alibaba.cola.ruleengine.core.NaturalRules;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
-import static org.assertj.core.api.Assertions.assertThat;
+import java.util.ArrayList;
public class PriorityTest {
+ RuleEngine ruleEngine;
+
+ @BeforeEach
+ public void setUp() {
+ ruleEngine = new DefaultRuleEngine();
+ }
+
+
@Test
public void testNoPriority() {
- DummyRule r1 = new DummyRule();
- DummyRule r2 = new DummyRule();
- DummyRule r3 = new DummyRule();
+ DummyRule r1 = new DummyRule(1);
+ DummyRule r2 = new DummyRule(2);
+ DummyRule r3 = new DummyRule(3);
// assertThat(rules).startsWith(r1).endsWith(r3);
}
@Test
- public void testPriority(){
+ public void testPriority() {
DummyRule r1 = new DummyRule(10);
DummyRule r2 = new DummyRule(3);
DummyRule r3 = new DummyRule(1);
-
-
// assertThat(rules).startsWith(r3).endsWith(r1);
}
+ @Test
+ public void test_natural_rule() {
+ DummyRule r1 = new DummyRule(10);
+ DummyRule r2 = new DummyRule(3);
+ DummyRule r3 = new DummyRule(1);
+ Facts facts = new Facts();
+ facts.put("number", 15);
+ Rule naturalRules = NaturalRules.of(r1, r2, r3);
+ ruleEngine.fire(naturalRules, facts);
+ }
- static class DummyRule extends AbstractRule {
-
- public DummyRule(){
+ static class DummyRule extends DefaultRule {
- }
- public DummyRule(int priority){
- super(priority);
+ public DummyRule(int priority) {
+ super("rule" + priority, null, priority, facts -> true, new ArrayList<>());
}
@Override
public boolean evaluate(Facts facts) {
- return false;
+ return true;
}
@Override
public void execute(Facts facts) {
-
+ System.out.println(facts.getFact("number").getValue());
}
@Override
public boolean apply(Facts facts) {
- return false;
+ System.out.println(name + ": " + facts.getFact("number").getValue());
+ return true;
}
}
}
diff --git a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleBuilderTest.java b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleBuilderTest.java
index dcedfe458..e18482efa 100644
--- a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleBuilderTest.java
+++ b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleBuilderTest.java
@@ -4,7 +4,7 @@
import com.alibaba.cola.ruleengine.api.Rule;
import com.alibaba.cola.ruleengine.api.RuleEngine;
import com.alibaba.cola.ruleengine.core.*;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
public class RuleBuilderTest {
diff --git a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleEngineTest.java b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleEngineTest.java
index 8eb470b59..1e637af13 100644
--- a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleEngineTest.java
+++ b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/RuleEngineTest.java
@@ -4,7 +4,7 @@
import com.alibaba.cola.ruleengine.api.Rule;
import com.alibaba.cola.ruleengine.api.RuleEngine;
import com.alibaba.cola.ruleengine.core.*;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
public class RuleEngineTest {
diff --git a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/fizzbuzz/FizzBuzzTest.java b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/fizzbuzz/FizzBuzzTest.java
index 25f36c858..a22549bfa 100644
--- a/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/fizzbuzz/FizzBuzzTest.java
+++ b/cola-components/cola-component-ruleengine/src/test/java/com/alibaba/cola/ruleengine/fizzbuzz/FizzBuzzTest.java
@@ -2,8 +2,9 @@
//import com.alibaba.cola.ruleengine.fizzbuzz.v1.FizzBuzz;
import com.alibaba.cola.ruleengine.fizzbuzz.v2.FizzBuzz;
-import org.assertj.core.api.Assertions;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
public class FizzBuzzTest {
@@ -14,7 +15,7 @@ public void num_given_1() {
//when
String result = FizzBuzz.count(input);
//then
- Assertions.assertThat(result).isEqualTo("1");
+ assertEquals(result, "1");
}
@Test
@@ -24,8 +25,7 @@ public void fizz_given_3() {
//when
String result = FizzBuzz.count(input);
//then
- Assertions.assertThat(result).isEqualTo("Fizz");
-
+ assertEquals(result, "Fizz");
}
@Test
@@ -35,7 +35,7 @@ public void buzz_given_5() {
//when
String result = FizzBuzz.count(input);
//then
- Assertions.assertThat(result).isEqualTo("Buzz");
+ assertEquals(result, "Buzz");
}
@Test
@@ -45,6 +45,6 @@ public void fizz_buzz_given_15() {
//when
String result = FizzBuzz.count(input);
//then
- Assertions.assertThat(result).isEqualTo("FizzBuzz");
+ assertEquals(result, "FizzBuzz");
}
}
diff --git a/cola-components/cola-component-statemachine/pom.xml b/cola-components/cola-component-statemachine/pom.xml
index 80ab78521..dc0eee61d 100644
--- a/cola-components/cola-component-statemachine/pom.xml
+++ b/cola-components/cola-component-statemachine/pom.xml
@@ -1,6 +1,14 @@
4.0.0
+
+
+ org.junit.jupiter
+ junit-jupiter
+ RELEASE
+ test
+
+
com.alibaba.cola
cola-components-parent
diff --git a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineChoiceTest.java b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineChoiceTest.java
index 6cea7bcdd..975b3f09c 100644
--- a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineChoiceTest.java
+++ b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineChoiceTest.java
@@ -5,8 +5,9 @@
import com.alibaba.cola.statemachine.StateMachine;
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
-import org.junit.Assert;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
/**
* @author dingchenchen
@@ -55,11 +56,11 @@ public void testChoice(){
StateMachine stateMachine = builder.build("ChoiceConditionMachine");
StateMachineTest.States target1 = stateMachine.fireEvent(StateMachineTest.States.STATE1, StateMachineTest.Events.EVENT1, new Context("1"));
- Assert.assertEquals(StateMachineTest.States.STATE1,target1);
+ Assertions.assertEquals(StateMachineTest.States.STATE1,target1);
StateMachineTest.States target2 = stateMachine.fireEvent(StateMachineTest.States.STATE1, StateMachineTest.Events.EVENT1, new Context("2"));
- Assert.assertEquals(StateMachineTest.States.STATE2,target2);
+ Assertions.assertEquals(StateMachineTest.States.STATE2,target2);
StateMachineTest.States target3 = stateMachine.fireEvent(StateMachineTest.States.STATE1, StateMachineTest.Events.EVENT1, new Context("3"));
- Assert.assertEquals(StateMachineTest.States.STATE3,target3);
+ Assertions.assertEquals(StateMachineTest.States.STATE3,target3);
}
private Condition checkCondition1() {
diff --git a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachinePlantUMLTest.java b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachinePlantUMLTest.java
index 84e02d4d6..e00761c2d 100644
--- a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachinePlantUMLTest.java
+++ b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachinePlantUMLTest.java
@@ -6,8 +6,8 @@
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
import com.alibaba.cola.statemachine.impl.Debugger;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import java.util.stream.Stream;
@@ -83,7 +83,7 @@ public boolean isSystemEvent(){
}
}
- @Before
+ @BeforeEach
public void init(){
Debugger.enableDebug();
}
diff --git a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java
index c20997edd..4c34f7a0c 100644
--- a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java
+++ b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineTest.java
@@ -8,9 +8,9 @@
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
import com.alibaba.cola.statemachine.exception.TransitionFailException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
-import org.junit.Assert;
-import org.junit.Test;
import java.util.List;
@@ -56,7 +56,7 @@ public void testExternalNormal() {
StateMachine stateMachine = builder.build(MACHINE_ID);
States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context());
- Assert.assertEquals(States.STATE2, target);
+ Assertions.assertEquals(States.STATE2, target);
}
@Test
@@ -72,7 +72,7 @@ public void testFail() {
builder.setFailCallback(new AlertFailCallback<>());
StateMachine stateMachine = builder.build(MACHINE_ID + "-testFail");
- Assert.assertThrows(TransitionFailException.class,
+ Assertions.assertThrows(TransitionFailException.class,
() -> stateMachine.fireEvent(States.STATE2, Events.EVENT1, new Context()));
}
@@ -88,8 +88,8 @@ public void testVerify() {
StateMachine stateMachine = builder.build(MACHINE_ID + "-testVerify");
- Assert.assertTrue(stateMachine.verify(States.STATE1, Events.EVENT1));
- Assert.assertFalse(stateMachine.verify(States.STATE1, Events.EVENT2));
+ Assertions.assertTrue(stateMachine.verify(States.STATE1, Events.EVENT1));
+ Assertions.assertFalse(stateMachine.verify(States.STATE1, Events.EVENT2));
}
@Test
@@ -104,7 +104,7 @@ public void testExternalTransitionsNormal() {
StateMachine stateMachine = builder.build(MACHINE_ID + "1");
States target = stateMachine.fireEvent(States.STATE2, Events.EVENT1, new Context());
- Assert.assertEquals(States.STATE4, target);
+ Assertions.assertEquals(States.STATE4, target);
}
@Test
@@ -119,7 +119,7 @@ public void testInternalNormal() {
stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context());
States target = stateMachine.fireEvent(States.STATE1, Events.INTERNAL_EVENT, new Context());
- Assert.assertEquals(States.STATE1, target);
+ Assertions.assertEquals(States.STATE1, target);
}
@Test
@@ -128,13 +128,13 @@ public void testExternalInternalNormal() {
Context context = new Context();
States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, context);
- Assert.assertEquals(States.STATE2, target);
+ Assertions.assertEquals(States.STATE2, target);
target = stateMachine.fireEvent(States.STATE2, Events.INTERNAL_EVENT, context);
- Assert.assertEquals(States.STATE2, target);
+ Assertions.assertEquals(States.STATE2, target);
target = stateMachine.fireEvent(States.STATE2, Events.EVENT2, context);
- Assert.assertEquals(States.STATE1, target);
+ Assertions.assertEquals(States.STATE1, target);
target = stateMachine.fireEvent(States.STATE1, Events.EVENT3, context);
- Assert.assertEquals(States.STATE3, target);
+ Assertions.assertEquals(States.STATE3, target);
}
private StateMachine buildStateMachine(String machineId) {
@@ -188,7 +188,7 @@ public void testMultiThread() {
Thread thread = new Thread(() -> {
StateMachine stateMachine = StateMachineFactory.get("testMultiThread");
States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context());
- Assert.assertEquals(States.STATE2, target);
+ Assertions.assertEquals(States.STATE2, target);
});
thread.start();
}
@@ -197,7 +197,7 @@ public void testMultiThread() {
Thread thread = new Thread(() -> {
StateMachine stateMachine = StateMachineFactory.get("testMultiThread");
States target = stateMachine.fireEvent(States.STATE1, Events.EVENT4, new Context());
- Assert.assertEquals(States.STATE4, target);
+ Assertions.assertEquals(States.STATE4, target);
});
thread.start();
}
@@ -206,7 +206,7 @@ public void testMultiThread() {
Thread thread = new Thread(() -> {
StateMachine stateMachine = StateMachineFactory.get("testMultiThread");
States target = stateMachine.fireEvent(States.STATE1, Events.EVENT3, new Context());
- Assert.assertEquals(States.STATE3, target);
+ Assertions.assertEquals(States.STATE3, target);
});
thread.start();
}
@@ -234,9 +234,9 @@ public void testParallel(){
System.out.println(state);
}
States target2 = stateMachine.fireEvent(StateMachineTest.States.STATE2, StateMachineTest.Events.EVENT2, new Context());
- Assert.assertEquals(States.STATE4,target2);
+ Assertions.assertEquals(States.STATE4,target2);
States target3 = stateMachine.fireEvent(StateMachineTest.States.STATE3, StateMachineTest.Events.EVENT2, new Context());
- Assert.assertEquals(States.STATE4,target3);
+ Assertions.assertEquals(States.STATE4,target3);
}
private Condition checkCondition() {
diff --git a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineUnNormalTest.java b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineUnNormalTest.java
index 9046d1e3c..548cefaf2 100644
--- a/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineUnNormalTest.java
+++ b/cola-components/cola-component-statemachine/src/test/java/com/alibaba/cola/test/StateMachineUnNormalTest.java
@@ -6,10 +6,8 @@
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
import com.alibaba.cola.statemachine.impl.StateMachineException;
-import org.junit.Assert;
-import org.junit.Test;
-
-import static com.alibaba.cola.test.StateMachineTest.MACHINE_ID;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
/**
* StateMachineUnNormalTest
@@ -31,40 +29,44 @@ public void testConditionNotMeet(){
StateMachine stateMachine = builder.build("NotMeetConditionMachine");
StateMachineTest.States target = stateMachine.fireEvent(StateMachineTest.States.STATE1, StateMachineTest.Events.EVENT1, new StateMachineTest.Context());
- Assert.assertEquals(StateMachineTest.States.STATE1,target);
+ Assertions.assertEquals(StateMachineTest.States.STATE1,target);
}
- @Test(expected = StateMachineException.class)
+ @Test
public void testDuplicatedTransition(){
- StateMachineBuilder builder = StateMachineBuilderFactory.create();
- builder.externalTransition()
- .from(StateMachineTest.States.STATE1)
- .to(StateMachineTest.States.STATE2)
- .on(StateMachineTest.Events.EVENT1)
- .when(checkCondition())
- .perform(doAction());
+ Assertions.assertThrows(StateMachineException.class, ()->{
+ StateMachineBuilder builder = StateMachineBuilderFactory.create();
+ builder.externalTransition()
+ .from(StateMachineTest.States.STATE1)
+ .to(StateMachineTest.States.STATE2)
+ .on(StateMachineTest.Events.EVENT1)
+ .when(checkCondition())
+ .perform(doAction());
- builder.externalTransition()
- .from(StateMachineTest.States.STATE1)
- .to(StateMachineTest.States.STATE2)
- .on(StateMachineTest.Events.EVENT1)
- .when(checkCondition())
- .perform(doAction());
+ builder.externalTransition()
+ .from(StateMachineTest.States.STATE1)
+ .to(StateMachineTest.States.STATE2)
+ .on(StateMachineTest.Events.EVENT1)
+ .when(checkCondition())
+ .perform(doAction());
+ });
}
- @Test(expected = StateMachineException.class)
+ @Test
public void testDuplicateMachine(){
- StateMachineBuilder builder = StateMachineBuilderFactory.create();
- builder.externalTransition()
- .from(StateMachineTest.States.STATE1)
- .to(StateMachineTest.States.STATE2)
- .on(StateMachineTest.Events.EVENT1)
- .when(checkCondition())
- .perform(doAction());
+ Assertions.assertThrows(StateMachineException.class, ()-> {
+ StateMachineBuilder builder = StateMachineBuilderFactory.create();
+ builder.externalTransition()
+ .from(StateMachineTest.States.STATE1)
+ .to(StateMachineTest.States.STATE2)
+ .on(StateMachineTest.Events.EVENT1)
+ .when(checkCondition())
+ .perform(doAction());
- builder.build("DuplicatedMachine");
- builder.build("DuplicatedMachine");
+ builder.build("DuplicatedMachine");
+ builder.build("DuplicatedMachine");
+ });
}
private Condition checkCondition() {
diff --git a/cola-components/cola-component-test-container/pom.xml b/cola-components/cola-component-test-container/pom.xml
index f0d8b4d3f..d91fddc4b 100644
--- a/cola-components/cola-component-test-container/pom.xml
+++ b/cola-components/cola-component-test-container/pom.xml
@@ -56,50 +56,33 @@
- org.springframework
- spring-context
- provided
+ org.springframework.boot
+ spring-boot-starter
+
- org.springframework
- spring-core
- provided
-
-
-
-
- javax.annotation
- javax.annotation-api
- provided
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+ junit
+ junit
+
+
commons-cli
commons-cli
-
- org.slf4j
- slf4j-api
+ org.junit.platform
+ junit-platform-launcher
+ 1.9.3
- ch.qos.logback
- logback-classic
- provided
-
-
- ch.qos.logback
- logback-core
- provided
-
-
-
-
- junit
- junit
- compile
+ org.junit.jupiter
+ junit-jupiter-engine
diff --git a/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestExecutor.java b/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestExecutor.java
index 08a214964..2c03004ac 100644
--- a/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestExecutor.java
+++ b/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestExecutor.java
@@ -1,23 +1,20 @@
package com.alibaba.cola.test;
+
import com.alibaba.cola.test.command.TestClassRunCmd;
import com.alibaba.cola.test.command.TestMethodRunCmd;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationContext;
-import org.springframework.util.StringUtils;
-
-import javax.annotation.Resource;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
+import org.junit.platform.engine.TestExecutionResult;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.TestExecutionListener;
+import org.junit.platform.launcher.TestIdentifier;
+import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
+
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.lang.reflect.Parameter;
+
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod;
/**
* TestExecutor
@@ -26,170 +23,69 @@
* @date 2020-11-17 3:42 PM
*/
public class TestExecutor {
- private String className;
- private String methodName;
- private Map testInstanceCache = new HashMap();
- private ApplicationContext context;
+ private Launcher launcher;
- public TestExecutor(ApplicationContext context){
- this.context = context;
+ public TestExecutor(Launcher launcher) {
+ this.launcher = launcher;
}
public void execute(TestClassRunCmd cmd) throws Exception {
- setClassName(cmd.getClassName());
-
- Class> testClz = Class.forName(className);
- Object testInstance = getTestInstance(testClz);
- runClassTest(cmd, testClz, testInstance);
+ Class> testClz = Class.forName(cmd.getClassName());
+ runClassTest(cmd, testClz);
}
public void execute(TestMethodRunCmd cmd) throws Exception {
- setClassName(cmd.getClassName());
- setMethodName(cmd.getMethodName());
-
- Class> testClz = Class.forName(className);
- Object testInstance = getTestInstance(testClz);
- runMethodTest(cmd, testClz, testInstance);
+ Class> testClz = Class.forName(cmd.getClassName());
+ runMethodTest(cmd, testClz, cmd.getMethodName());
}
- private void runMethodTest(TestMethodRunCmd cmd, Class> testClz, Object testInstance) throws Exception{
- Method beforeMethod = BeanMetaUtils.findMethod(testClz, Before.class);
- Method afterMethod = BeanMetaUtils.findMethod(testClz, After.class);
- Method method = testClz.getMethod(methodName);
+ private void runMethodTest(TestMethodRunCmd cmd, Class> testClz, String methodName) throws Exception {
+ // 获取测试类的方法参数类型name,只支持单参数
+ String paramTypeName = extractParamTypeName(testClz, methodName);
- //invoke before method
- invokeMethod(testInstance, beforeMethod);
- //notifier.fireTestStarted(method, colaDes.getDescription());
+ // 创建测试方法
+ LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
+ .request()
+ .selectors(selectMethod(testClz, methodName, paramTypeName))
+ .build();
- //invoke test method
- invokeMethod(testInstance, method);
- //notifier.fireTestFinished(method, colaDes.getDescription());
-
- //invoke after method
- invokeMethod(testInstance, afterMethod);
- //notifier.fireTestRunFinished(colaDes.getDescription());
- }
-
- private Object getTestInstance(Class> testClz) throws Exception{
- if(testInstanceCache.get(className) != null) {
- return testInstanceCache.get(className);
- }
- Object testInstance = testClz.newInstance();
- injectWiredBean(testClz, testInstance);
- return testInstance;
+ // 运行测试方法
+ launcher.execute(request, new MyTestExecutionListener());
}
- private void runClassTest(TestClassRunCmd cmd, Class> testClz, Object testInstance)throws Exception{
- Method[] allMethods = testClz.getMethods();
- Method beforeMethod = null;
- Method afterMethod = null;
- List testMethods = new ArrayList();
- for (Method method : allMethods){
- Annotation[] annotations = method.getAnnotations();
- for(Annotation annotation : annotations){
- if(annotation instanceof Before){
- beforeMethod = method;
- break;
- }
- if(annotation instanceof After){
- afterMethod = method;
- break;
- }
- if(annotation instanceof Test || method.getName().startsWith("test")){
- testMethods.add(method);
- break;
+ private String extractParamTypeName(Class> testClz, String methodName) {
+ for (Method method : testClz.getMethods()) {
+ if(methodName.equals(method.getName())){
+ for (Parameter parameter : method.getParameters()) {
+ return parameter.getType().getName();
}
}
}
-
- //invoke before method
- invokeMethod(testInstance, beforeMethod);
- //invoke test methods
- for(Method testMethod: testMethods){
-
- invokeMethod(testInstance, testMethod);
-
- }
- //invoke after method
- invokeMethod(testInstance, afterMethod);
+ return "";
}
- private static void invokeMethod(Object obj, Method method) throws Exception{
- if (method == null) {
- return;
- }
- method.invoke(obj);
- }
- private void injectWiredBean(Class> testClz, Object testInstance) {
- Field[] fields = testClz.getDeclaredFields();
- if(fields == null) {
- return;
- }
- for(Field field : fields) {
- String beanName = field.getName();
- Annotation autowiredAnn = field.getDeclaredAnnotation(Autowired.class);
- Annotation resourceAnn = field.getDeclaredAnnotation(Resource.class);
- if (autowiredAnn == null && resourceAnn == null) {
- continue;
- }
- trySetFieldValue(field, testInstance, beanName);
- }
+ private void runClassTest(TestClassRunCmd cmd, Class> testClz) {
+ // 创建测试类
+ LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
+ .request()
+ .selectors(selectClass(testClz))
+ .build();
+
+ // 运行测试方法
+ launcher.execute(request, new MyTestExecutionListener());
}
- private void trySetFieldValue(Field field, Object testInstance, String beanName){
- try {
- field.setAccessible(true);
- field.set(testInstance, context.getBean(beanName));
- return;
- } catch (IllegalArgumentException e){
- if(!StringUtils.isEmpty(e.getMessage()) && e.getMessage().indexOf("\\$Proxy") > 0){
- System.err.println("此错误一般是实际类被代理导致,请尝试把字段类型改为接口!");
- throw e;
+ static class MyTestExecutionListener implements TestExecutionListener {
+ @Override
+ public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
+ if (testExecutionResult.getStatus() == TestExecutionResult.Status.FAILED) {
+ // 处理测试失败的情况,例如记录日志或发送通知
+ System.err.println("Test failed: " + testIdentifier.getDisplayName());
+ testExecutionResult.getThrowable().get().printStackTrace();
}
- }catch (BeansException | IllegalAccessException e) {
- System.err.println("根据beanName查找失败,尝试byType查找");
- }
-
- try {
- field.set(testInstance, context.getBean(field.getType()));
- } catch (Exception innerE) {
- innerE.printStackTrace();
- System.err.println("oops!!! "+beanName + " can not be injected to "+ className);
}
}
-
- /**
- * @return the className
- */
- public String getClassName() {
- return className;
- }
-
-
- /**
- * @param className the className to set
- */
- public void setClassName(String className) {
- this.className = className;
- }
-
-
- /**
- * @return the methodName
- */
- public String getMethodName() {
- return methodName;
- }
-
-
- /**
- * @param methodName the methodName to set
- */
- public void setMethodName(String methodName) {
- this.methodName = methodName;
- }
-
-}
\ No newline at end of file
+}
diff --git a/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestsContainer.java b/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestsContainer.java
index e924e0a8f..d09b83be2 100644
--- a/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestsContainer.java
+++ b/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/TestsContainer.java
@@ -2,11 +2,10 @@
import com.alibaba.cola.test.command.AbstractCommand;
import com.alibaba.cola.test.command.GuideCmd;
-import org.springframework.beans.BeansException;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.core.LauncherFactory;
import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
+import org.springframework.util.ObjectUtils;
import java.io.BufferedReader;
import java.io.IOException;
@@ -26,49 +25,63 @@
* @author Frank Zhang
* @date 2020-11-17 3:35 PM
*/
-@Component
-public class TestsContainer implements ApplicationContextAware {
+public class TestsContainer {
private static ApplicationContext context;
+ private static Launcher launcher;
private static TestExecutor testExecutor;
private static AtomicBoolean initFlag = new AtomicBoolean(false);
- public static void init(ApplicationContext context){
- if(!initFlag.compareAndSet(false, true)) {
- return;
- }
- if(context == null){
- testExecutor = new TestExecutor(TestsContainer.context);
- }else {
- testExecutor = new TestExecutor(context);
+
+ /**
+ * 如果要用到Junit5的Extension功能,需要显示的提供Launcher
+ *
+ * @param context ApplicationContext to be provided
+ * @param launcher 运行Junit5测试用例的Launcher, 如果不提供,默认会自己创建一个
+ */
+ public static void start(ApplicationContext context, Launcher launcher) {
+ TestsContainer.context = context;
+ if (launcher != null) {
+ TestsContainer.launcher = launcher;
+ } else {
+ TestsContainer.launcher = LauncherFactory.create();
}
+ testExecutor = new TestExecutor(TestsContainer.launcher);
+ monitorConsole();
+ }
+
+ /**
+ * 使用Junit5的launcher之后,不再需要ApplicationContext,框架会自己处理Spring的依赖关系
+ * @param launcher
+ */
+ public static void start(Launcher launcher) {
+ start(null, launcher);
}
/**
* TestsContainer is optional to be in Spring Container
+ *
* @param context ApplicationContext to be provided
*/
public static void start(ApplicationContext context) {
- TestsContainer.context = context;
- start();
+ start(context, null);
}
/**
- * TestsContainer must be within Spring Container
+ * TestsContainer without Spring Container
*/
- public static void start(){
- init(TestsContainer.context);
- monitorConsole();
+ public static void start() {
+ start(null, null);
}
- public static void execute(String input){
- if(StringUtils.isEmpty(input)){
+ public static void execute(String input) {
+ if (ObjectUtils.isEmpty(input)) {
return;
}
input = input.trim();
AbstractCommand command = AbstractCommand.createCmd(input);
- if (command == null){
+ if (command == null) {
System.err.println("Your input is not a valid qualified name");
return;
}
@@ -80,12 +93,7 @@ public static TestExecutor getTestExecutor() {
return testExecutor;
}
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- context = applicationContext;
- }
-
- private static void monitorConsole(){
+ private static void monitorConsole() {
BufferedReader bufferRead = new BufferedReader(new InputStreamReader(
System.in));
String input = GuideCmd.GUIDE_HELP;
@@ -94,7 +102,7 @@ private static void monitorConsole(){
execute(input);
} catch (Exception e) {
e.printStackTrace();
- } catch (Error e){
+ } catch (Error e) {
e.printStackTrace();
break;
}
@@ -106,4 +114,4 @@ private static void monitorConsole(){
}
}
}
-}
\ No newline at end of file
+}
diff --git a/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/command/AbstractCommand.java b/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/command/AbstractCommand.java
index 1a70d68f8..bee53fde1 100644
--- a/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/command/AbstractCommand.java
+++ b/cola-components/cola-component-test-container/src/main/java/com/alibaba/cola/test/command/AbstractCommand.java
@@ -1,7 +1,7 @@
package com.alibaba.cola.test.command;
import org.apache.commons.cli.*;
-import org.springframework.util.StringUtils;
+import org.springframework.util.ObjectUtils;
import java.util.HashMap;
import java.util.Map;
@@ -13,7 +13,7 @@
* @date 2020-11-17 4:33 PM
*/
public abstract class AbstractCommand {
- private static CommandLineParser parser = new DefaultParser();
+ private static final CommandLineParser parser = new DefaultParser();
protected static AbstractCommand curCmd;
protected static AbstractCommand preCmd;
@@ -57,22 +57,6 @@ public CommandLine parse(){
return null;
}
- public Object getParam(String key){
- return params.get(key);
- }
-
- public void putParam(String key, Object value){
- params.put(key, value);
- }
-
- public String getStringParam(String key){
- Object value = params.get(key);
- if(value == null){
- return EMPTY;
- }
- return value.toString();
- }
-
public boolean isEclipseMethod(String input) {
return input.indexOf("(") > 0 ;
}
@@ -86,7 +70,7 @@ public CommandLine getCommandLine() {
}
public static AbstractCommand createCmd(String cmdRaw){
- if(StringUtils.isEmpty(cmdRaw)){
+ if(ObjectUtils.isEmpty(cmdRaw)){
return null;
}
@@ -111,4 +95,4 @@ public static AbstractCommand createCmd(String cmdRaw){
return command;
}
-}
\ No newline at end of file
+}
diff --git a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/Demo.java b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/Demo.java
index 90f12a9e2..e1d4b9838 100644
--- a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/Demo.java
+++ b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/Demo.java
@@ -1,12 +1,16 @@
package com.alibaba.cola.test;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+@Slf4j
public class Demo {
- @Before
+ @BeforeEach
public void before(){
System.out.println("before action");
}
@@ -14,6 +18,8 @@ public void before(){
@Test
public void testOne(){
System.out.println("test one");
+ Assertions.assertEquals(1,1);
+ System.out.println("test one end");
}
@Test
@@ -21,7 +27,17 @@ public void testTwo(){
System.out.println("test two");
}
- @After
+ @Test
+ void testThree(){
+ System.out.println("test three");
+ }
+
+ @Test
+ public void testParam(String param){
+ System.out.println("hello param");
+ }
+
+ @AfterEach
public void after(){
System.out.println("after action");
}
diff --git a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/DemoWithExtension.java b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/DemoWithExtension.java
new file mode 100644
index 000000000..b09530351
--- /dev/null
+++ b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/DemoWithExtension.java
@@ -0,0 +1,67 @@
+package com.alibaba.cola.test;
+
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+
+@SpringBootTest(classes = SpringBootConfig.class)
+@ExtendWith(LoggingExtension.class)
+public class DemoWithExtension {
+
+ @Autowired
+ private Demo demo;
+
+ @BeforeEach
+ public void before() {
+ System.out.println("=====before");
+ }
+
+ @Test
+ public void testParam(String param) {
+ System.out.println("hello : " + param);
+ }
+
+ @Test
+ public void testMethod1() {
+ System.out.println("Begin testMethod1");
+ demo.testOne();
+ System.out.println("End testMethod1");
+ }
+
+ @Test
+ public void testMethod2() {
+ System.out.println("Begin testMethod2");
+ demo.testTwo();
+ System.out.println("End testMethod2");
+ }
+
+ @AfterEach
+ public void after() {
+ System.out.println("=====after");
+ }
+}
+
+
+class LoggingExtension implements BeforeEachCallback, ParameterResolver {
+ @Override
+ public void beforeEach(ExtensionContext context) throws Exception {
+ System.out.println("Executing test method: " + context.getRequiredTestMethod().getName());
+ }
+
+ @Override
+ public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+ return true;
+ }
+
+ @Override
+ public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+ System.out.println("resolveParameter: " + parameterContext);
+ return null;
+ }
+}
diff --git a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/SpringBootConfig.java b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/SpringBootConfig.java
new file mode 100644
index 000000000..27291b9d0
--- /dev/null
+++ b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/SpringBootConfig.java
@@ -0,0 +1,7 @@
+package com.alibaba.cola.test;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringBootConfig {
+}
diff --git a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/SpringConfig.java b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/SpringConfig.java
index 5f74f8f1f..9b7783e58 100644
--- a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/SpringConfig.java
+++ b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/SpringConfig.java
@@ -1,5 +1,6 @@
package com.alibaba.cola.test;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@@ -13,4 +14,8 @@
@ComponentScan
public class SpringConfig {
+ @Bean("demo")
+ public Demo generateDemo(){
+ return new Demo();
+ }
}
diff --git a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/TestsContainerTest.java b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/TestsContainerTest.java
index bf500cc3c..d4d53aff6 100644
--- a/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/TestsContainerTest.java
+++ b/cola-components/cola-component-test-container/src/test/java/com/alibaba/cola/test/TestsContainerTest.java
@@ -11,8 +11,6 @@
*/
public class TestsContainerTest {
public static void main(String[] args) {
- ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
-
TestsContainer.start();
}
}
diff --git a/cola-components/cola-component-unittest/.gitignore b/cola-components/cola-component-unittest/.gitignore
new file mode 100644
index 000000000..9a1655a05
--- /dev/null
+++ b/cola-components/cola-component-unittest/.gitignore
@@ -0,0 +1,26 @@
+target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+out/
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+bin/
+doc/
+.DS_Store
diff --git a/cola-components/cola-component-unittest/README.md b/cola-components/cola-component-unittest/README.md
new file mode 100644
index 000000000..dca7cc468
--- /dev/null
+++ b/cola-components/cola-component-unittest/README.md
@@ -0,0 +1,52 @@
+## 原理
+通过注解AOP,提供service级别的logging和exception处理。
+
+通过Spring Boot的autoConfig机制进行加载,无需手动配置,只需要添加如下依赖即可:
+```xml
+
+ com.alibaba.lst.tech.shared
+ catch-log-starter
+
+```
+
+兼容普通的HSF service和Mtop service,具体做法可以查看代码`ResponseHandler`
+```java
+public class ResponseHandler {
+
+ public static Object handle(Class returnType, String errCode, String errMsg){
+ if (isColaResponse(returnType)){
+ return handleColaResponse(returnType, errCode, errMsg);
+ }
+ if(isMtopResponse(returnType)){
+ return handleMtopResponse(returnType, errCode, errMsg);
+ }
+ return null;
+ }
+ ...
+ }
+
+```
+
+
+## 使用介绍
+1、在需要处理的Service类上面加上@CatchAndLog注解
+```java
+@CatchAndLog
+public class GrouponServiceImpl implements GrouponService
+```
+
+2、logback-test.xml为组件开启DEGUG level的日志输出
+```xml
+
+
+```
+
+3、如果在控制台看到如下的日志输出,说明CatchAndLog已经在做AOP拦截
+```xml
+DEBUG c.a.l.t.s.catchlog.CatchLogAspect - Start processing: GrouponServiceImpl.queryGrouponItemDetail(..)
+DEBUG c.a.l.t.s.catchlog.CatchLogAspect - REQUEST : 257
+
+DEBUG c.a.l.t.s.catchlog.CatchLogAspect - RESPONSE : {"errCode":"UNKNOWN_ERROR"...}
+DEBUG c.a.l.t.s.catchlog.CatchLogAspect - COST : 1329ms
+```
+
diff --git a/cola-components/cola-component-unittest/pom.xml b/cola-components/cola-component-unittest/pom.xml
new file mode 100644
index 000000000..88608d62f
--- /dev/null
+++ b/cola-components/cola-component-unittest/pom.xml
@@ -0,0 +1,100 @@
+
+
+ 4.0.0
+
+ com.alibaba.cola
+ cola-components-parent
+ 4.4.0-SNAPSHOT
+
+
+ cola-component-unittest
+ jar
+ ${project.artifactId}:${project.version}
+ ${project.artifactId}
+ https://github.com/alibaba/COLA
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+
+ it.ozimov
+ embedded-redis
+ 0.7.3
+
+
+ redis.clients
+ jedis
+ 5.1.0
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+
+
+ com.github.ppodgorsek
+ spring-test-dbunit-core
+ 5.2.0
+
+
+ org.dbunit
+ dbunit
+ 2.7.0
+
+
+
+
+ org.springframework.kafka
+ spring-kafka
+
+
+ org.springframework.kafka
+ spring-kafka-test
+
+
+
+
+ org.wiremock
+ wiremock-standalone
+ 3.0.1
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+ com.alibaba.cola
+ cola-component-test-container
+ 4.4.0-SNAPSHOT
+ test
+
+
+ org.awaitility
+ awaitility
+
+
+
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/FixtureLoader.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/FixtureLoader.java
new file mode 100644
index 000000000..518e0eb28
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/FixtureLoader.java
@@ -0,0 +1,29 @@
+package com.alibaba.cola.unittest;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.StreamUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+public class FixtureLoader {
+
+ public static String loadResource(String resourcePath) {
+ log.info("Fixture resource location: " + resourcePath);
+ // 创建一个 ClassPathResource 对象
+ ClassPathResource resource = new ClassPathResource(resourcePath);
+
+ // 使用 withResource 来自动关闭输入流
+ String content = "";
+ try (InputStream inputStream = resource.getInputStream()) {
+ content = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e.getMessage());
+ }
+ return content;
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/KafkaExtension.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/KafkaExtension.java
new file mode 100644
index 000000000..455c46c92
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/KafkaExtension.java
@@ -0,0 +1,73 @@
+package com.alibaba.cola.unittest.kafka;
+
+import com.alibaba.cola.unittest.FixtureLoader;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.common.serialization.Serializer;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.junit.jupiter.api.extension.*;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.support.serializer.JsonSerializer;
+import org.springframework.kafka.test.EmbeddedKafkaBroker;
+import org.springframework.kafka.test.utils.KafkaTestUtils;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+public class KafkaExtension implements BeforeAllCallback, BeforeEachCallback {
+
+ private EmbeddedKafkaBroker embeddedKafkaBroker;
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ @Override
+ public void beforeAll(ExtensionContext context) throws Exception {
+ try {
+ EmbeddedKafkaBroker embeddedKafkaBroker = (EmbeddedKafkaBroker) SpringExtension.getApplicationContext(context).getBean(EmbeddedKafkaBroker.class);
+ log.debug("embeddedKafkaBroker:" + embeddedKafkaBroker);
+ this.embeddedKafkaBroker = embeddedKafkaBroker;
+ } catch (NoSuchBeanDefinitionException e) {
+ log.error("Please add @EmbeddedKafka for your test", e);
+ throw e;
+ }
+ }
+
+ @Override
+ public void beforeEach(ExtensionContext context) throws Exception {
+ ProduceMessage produceMessage = context.getElement().get().getAnnotation(ProduceMessage.class);
+ if (Objects.nonNull(produceMessage)) {
+ log.info("begin produce message for kafka");
+ String location = produceMessage.value();
+ MessageData messageData = objectMapper.readValue(FixtureLoader.loadResource(location), MessageData.class);
+ log.debug("messageData: " + messageData);
+
+ //get producer
+ KafkaTemplate producer = this.createProducer();
+
+ List messages = messageData.getMessages();
+ int count = 0;
+ for (ObjectNode message : messages) {
+ // TODO:add key support later
+ // Optional recordKey = Optional.ofNullable(record.remove("$KEY$")).map(JsonNode::asText);
+ producer.send(messageData.getTopic(), message);
+
+ log.info("produce message[{}:{}]: {}", new Object[]{messageData.getTopic(), ++count, message});
+ }
+ }
+ }
+
+ public KafkaTemplate createProducer(Serializer keySerializer, Serializer valueSerializer) {
+ Map props = KafkaTestUtils.producerProps(this.embeddedKafkaBroker);
+ return new KafkaTemplate(new DefaultKafkaProducerFactory(props, keySerializer, valueSerializer));
+ }
+
+ public KafkaTemplate createProducer() {
+ return this.createProducer(new StringSerializer(), new JsonSerializer());
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/MessageData.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/MessageData.java
new file mode 100644
index 000000000..034ad24b9
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/MessageData.java
@@ -0,0 +1,16 @@
+package com.alibaba.cola.unittest.kafka;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+@Data
+@EqualsAndHashCode
+@ToString
+public class MessageData {
+ private String topic;
+ private List messages;
+}
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/ProduceMessage.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/ProduceMessage.java
new file mode 100644
index 000000000..67314f275
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/kafka/ProduceMessage.java
@@ -0,0 +1,13 @@
+package com.alibaba.cola.unittest.kafka;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target( {ElementType.TYPE, ElementType.METHOD})
+public @interface ProduceMessage {
+
+ String value();
+}
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/ExpectRedis.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/ExpectRedis.java
new file mode 100644
index 000000000..7bad61b68
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/ExpectRedis.java
@@ -0,0 +1,26 @@
+package com.alibaba.cola.unittest.redis;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target( {ElementType.TYPE, ElementType.METHOD})
+public @interface ExpectRedis {
+ /**
+ * 测试校验数据路径, 通常放在测试夹具(fixture)下面
+ */
+ String value();
+
+ /**
+ * 重试等待key生效的间隔(ms)
+ */
+ long interval() default 200L;
+
+ /**
+ * 验证超时时间(ms)
+ */
+ long timeout() default 3000L;
+}
+
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/RedisData.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/RedisData.java
new file mode 100644
index 000000000..1ec748a9f
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/RedisData.java
@@ -0,0 +1,20 @@
+package com.alibaba.cola.unittest.redis;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+/**
+ * 使用jackson:https://zhuanlan.zhihu.com/p/646744855
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class RedisData {
+ // Map
+ private Map records;
+}
+
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/RedisExtension.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/RedisExtension.java
new file mode 100644
index 000000000..029939d6f
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/RedisExtension.java
@@ -0,0 +1,111 @@
+package com.alibaba.cola.unittest.redis;
+
+import com.alibaba.cola.unittest.FixtureLoader;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.extern.slf4j.Slf4j;
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.extension.*;
+import redis.clients.jedis.Jedis;
+import redis.embedded.RedisServer;
+
+import java.time.Duration;
+import java.util.*;
+
+@Slf4j
+public class RedisExtension implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback {
+ ObjectMapper objectMapper = new ObjectMapper();
+ //default port is 6397
+ private static RedisServer redisServer;
+ public static Jedis jedis;
+ private static boolean isStarted;
+
+ @Override
+ public void afterEach(ExtensionContext context) throws Exception {
+
+ ExpectRedis expectRedis = context.getElement().get().getAnnotation(ExpectRedis.class);
+ if (Objects.nonNull(expectRedis)) {
+ log.info("after each, check redis result");
+ String location = expectRedis.value();
+ long interval = expectRedis.interval();
+ long timeout = expectRedis.timeout();
+ RedisData redisData = objectMapper.readValue(FixtureLoader.loadResource(location), RedisData.class);
+ redisData.getRecords().forEach((key, content) -> {
+ await(interval, timeout, key);
+ String expect = content.textValue();
+ String actual = jedis.get(key);
+ log.debug("expect: " + expect);
+ log.debug("actual: " + actual);
+ Assertions.assertEquals(expect, actual);
+ });
+ }
+ }
+
+ private void await(long interval, long timeout, String key) {
+ Awaitility.await().pollInterval(Duration.ofMillis(interval)).atMost(Duration.ofMillis(timeout))
+ .until(() -> jedis.exists(key));
+ }
+
+ @Override
+ public void beforeEach(ExtensionContext context) throws Exception {
+ SetupRedis setupRedis = context.getElement().get().getAnnotation(SetupRedis.class);
+ if (Objects.nonNull(setupRedis)) {
+ log.info("before each, setup redis");
+ String location = setupRedis.value();
+ RedisData redisData = objectMapper.readValue(FixtureLoader.loadResource(location), RedisData.class);
+ log.debug("redisData: " + redisData);
+ redisData.getRecords().forEach((key, jsonNode) -> {
+ processJsonNode(key, jsonNode);
+ });
+ }
+ }
+
+ private void processJsonNode(String key, JsonNode jsonNode) {
+ JsonNodeType nodeType = jsonNode.getNodeType();
+ log.debug("set redis record: TYPE--> {} , KEY--> {}, VALUE--> {}", nodeType, key, jsonNode);
+ if (nodeType == JsonNodeType.STRING) {
+ jedis.set(key, jsonNode.textValue());
+ return;
+ }
+ if (nodeType == JsonNodeType.ARRAY) {
+ List elements = new ArrayList<>();
+ jsonNode.forEach(item -> {
+ String itemStr = item.isValueNode() ? item.asText() : item.toString();
+ elements.add(itemStr);
+ });
+ jedis.sadd(key, elements.toArray(new String[0]));
+ return;
+ }
+ if (nodeType == JsonNodeType.OBJECT) {
+ Map map = new HashMap<>();
+ ObjectNode objectNode = (ObjectNode) jsonNode;
+ objectNode.fields()
+ .forEachRemaining(
+ field -> {
+ String value = field.getValue().isValueNode() ? field.getValue().asText() : field.getValue().toString();
+ map.put(field.getKey(), value);
+ });
+ jedis.hmset(key, map);
+ }
+ }
+
+ @Override
+ public void beforeAll(ExtensionContext context) {
+ try {
+ if (redisServer == null && !isStarted) {
+ redisServer = new RedisServer(); //default port is 6379
+ redisServer.start();
+ log.debug("Redis server started");
+ }
+ } catch (Exception e) {
+ isStarted = true;
+ log.warn("Redis Server may already started, just ignore this exception:" + e.getMessage());
+ }
+ if (jedis == null) {
+ jedis = new Jedis("localhost", 6379);
+ }
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/SetupRedis.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/SetupRedis.java
new file mode 100644
index 000000000..aa761c07d
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/redis/SetupRedis.java
@@ -0,0 +1,18 @@
+package com.alibaba.cola.unittest.redis;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 测试启动时注入redis记录
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target( {ElementType.TYPE, ElementType.METHOD})
+public @interface SetupRedis {
+ /**
+ * 测试准备数据路径, 通常放在测试夹具(fixture)下面,比如:/fixture/job.json
+ */
+ String value();
+}
diff --git a/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/wiremock/WireMockRegister.java b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/wiremock/WireMockRegister.java
new file mode 100644
index 000000000..92083d7c2
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/main/java/com/alibaba/cola/unittest/wiremock/WireMockRegister.java
@@ -0,0 +1,13 @@
+package com.alibaba.cola.unittest.wiremock;
+
+import com.alibaba.cola.unittest.FixtureLoader;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.stubbing.StubMapping;
+
+public class WireMockRegister {
+
+ public static void registerStub(WireMock wireMock, String resourcePath){
+ StubMapping stubMapping = StubMapping.buildFrom(FixtureLoader.loadResource(resourcePath));
+ wireMock.register(stubMapping);
+ }
+}
diff --git a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/Application.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/Application.java
similarity index 75%
rename from cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/Application.java
rename to cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/Application.java
index 480f81bbd..7ed1834a1 100644
--- a/cola-components/cola-component-extension-starter/src/test/java/com/alibaba/cola/extension/test/Application.java
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/Application.java
@@ -1,4 +1,4 @@
-package com.alibaba.cola.extension.test;
+package com.alibaba.cola.unittest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,7 +9,7 @@
* @author Frank Zhang
* @date 2020-11-10 3:58 PM
*/
-@SpringBootApplication
+@SpringBootApplication(scanBasePackages = {"com.alibaba.cola.unittest"})
public class Application {
public static void main(String[] args) {
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/TestsContainerBoot.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/TestsContainerBoot.java
new file mode 100644
index 000000000..4a6c13ae5
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/TestsContainerBoot.java
@@ -0,0 +1,9 @@
+package com.alibaba.cola.unittest;
+
+import com.alibaba.cola.test.TestsContainer;
+
+public class TestsContainerBoot {
+ public static void main(String[] args) {
+ TestsContainer.start();
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/DBSetupTest.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/DBSetupTest.java
new file mode 100644
index 000000000..49f3f6968
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/DBSetupTest.java
@@ -0,0 +1,31 @@
+package com.alibaba.cola.unittest.db;
+
+import com.github.springtestdbunit.DbUnitTestExecutionListener;
+import com.github.springtestdbunit.annotation.DatabaseSetup;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+// 关于TestExecutionListener: https://www.baeldung.com/spring-testexecutionlistener
+@SpringBootTest
+@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DbUnitTestExecutionListener.class })
+public class DBSetupTest {
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @Test
+ @DatabaseSetup("/fixture/db/sample-data.xml")
+ public void testFind() throws Exception {
+ List personList = personRepository.find("hil");
+ System.out.println(personList);
+ assertEquals(1, personList.size());
+ assertEquals("Phillip", personList.get(0).getFirstName());
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/Person.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/Person.java
new file mode 100644
index 000000000..b9ad42c91
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/Person.java
@@ -0,0 +1,59 @@
+package com.alibaba.cola.unittest.db;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.NamedQueries;
+import jakarta.persistence.NamedQuery;
+
+@Entity
+@NamedQueries({ @NamedQuery(name = "Person.find", query = "SELECT p from Person p where p.firstName like :name "
+ + "or p.lastName like :name") })
+public class Person {
+
+ @Id
+ private int id;
+
+ private String title;
+
+ private String firstName;
+
+ private String lastName;
+
+ public int getId() {
+ return id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ @Override
+ public String toString() {
+ return "Person{" +
+ "id=" + id +
+ ", title='" + title + '\'' +
+ ", firstName='" + firstName + '\'' +
+ ", lastName='" + lastName + '\'' +
+ '}';
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/PersonRepository.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/PersonRepository.java
new file mode 100644
index 000000000..fe3edf4a3
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/db/PersonRepository.java
@@ -0,0 +1,30 @@
+package com.alibaba.cola.unittest.db;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.Query;
+import jakarta.transaction.Transactional;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+@Transactional
+public class PersonRepository {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @SuppressWarnings("unchecked")
+ public List find(String name) {
+ Query query = entityManager.createNamedQuery("Person.find");
+ query.setParameter("name", "%" + name + "%");
+ return query.getResultList();
+ }
+
+ public void remove(int personId) {
+ Person person = entityManager.find(Person.class, personId);
+ entityManager.remove(person);
+ }
+
+}
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/kafka/KafkaConsumer.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/kafka/KafkaConsumer.java
new file mode 100644
index 000000000..69c9611ad
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/kafka/KafkaConsumer.java
@@ -0,0 +1,40 @@
+package com.alibaba.cola.unittest.kafka;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class KafkaConsumer {
+
+
+ private String payload;
+ boolean isFinished;
+
+ @KafkaListener(topics = "${test.topic}", groupId = "testGroup")
+ public void receive(ConsumerRecord, ?> consumerRecord) {
+ log.info("received payload='{}'", consumerRecord.toString());
+ payload = consumerRecord.toString();
+
+ processBiz();
+
+ isFinished = true;
+ }
+
+ private void processBiz() {
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ public String getPayload() {
+ return payload;
+ }
+
+}
+
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/kafka/KafkaExtensionTest.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/kafka/KafkaExtensionTest.java
new file mode 100644
index 000000000..c4758d108
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/kafka/KafkaExtensionTest.java
@@ -0,0 +1,34 @@
+package com.alibaba.cola.unittest.kafka;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.awaitility.Awaitility.await;
+
+@Slf4j
+@SpringBootTest
+@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" })
+@ExtendWith(KafkaExtension.class)
+public class KafkaExtensionTest {
+
+ @Autowired
+ private KafkaConsumer consumer;
+
+ @Test
+ @ProduceMessage("/fixture/kafka/produce-message.json")
+ public void testProduceMessage(){
+ log.info("test produce message");
+
+ // 等待消息业务处理,每100毫秒poll一下,最长等待10秒
+ await().atMost(10, TimeUnit.SECONDS).pollInterval(100, TimeUnit.MILLISECONDS)
+ .until(() -> consumer.isFinished);
+
+ log.info("consume message finished");
+ }
+}
+
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/redis/RedisExtensionTest.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/redis/RedisExtensionTest.java
new file mode 100644
index 000000000..675892334
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/redis/RedisExtensionTest.java
@@ -0,0 +1,87 @@
+package com.alibaba.cola.unittest.redis;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.Map;
+import java.util.Set;
+
+@ExtendWith(RedisExtension.class)
+public class RedisExtensionTest {
+
+ /**
+ * json String 的内容,注意如果是String的话,需要用转义符号\,转义双引号
+ * {
+ * "records": {
+ * "topo:child_job:222": "{\"id\":\"12345678-1234-1234-1234-childJob0000\",\"parent_job_id\":\"12345678-1234-1234-1234-noParentJob0\",\"resource_id\":\"1.1.1.4\",\"status\":\"success\"}",
+ * "topo:child_job:333": "{\"id\":\"12345678-1234-1234-1234-childJob0000\"}"
+ * }
+ * }
+ */
+ @Test
+ @SetupRedis("/fixture/redis/string-setup.json")
+ public void testString() {
+ System.out.println("test String SetupRedis");
+ }
+
+ /**
+ * json array 的内容:
+ * {
+ * "records": {
+ * "xlink:10.0.0.11:port": [
+ * "30000000-0000-0000-0000-000000000001",
+ * "30000000-0000-0000-0000-000000000002"
+ * ]
+ * }
+ * }
+ */
+ @Test
+ @SetupRedis("/fixture/redis/array-setup.json")
+ public void testArray() {
+ System.out.println("test array SetupRedis");
+ Set result = RedisExtension.jedis.smembers("test:array");
+ System.out.println("test result : " + result);
+ Assertions.assertEquals(2, result.size());
+ }
+
+ /**
+ * json 的object在redis里面是用hash存储,内容如下:
+ * {
+ * "records": {
+ * "xlink:hyper_cluster_port:30000000-0000-0000-0000-000000000001": {
+ * "version": 1,
+ * "json": {
+ * "id": "30000000-0000-0000-0000-000000000001",
+ * "name": "port-01",
+ * "project_id": "7a9941d34fc1497d8d0797429ecfd354",
+ * "provisioning_status": "active",
+ * "created_at": "2024-01-01T12:00:00Z",
+ * "updated_at": "2024-01-01T12:00:00Z"
+ * }
+ * }
+ * }
+ * }
+ */
+ @Test
+ @SetupRedis("/fixture/redis/hash-setup.json")
+ public void testHash() {
+ System.out.println("test hash SetupRedis");
+ Map result = RedisExtension.jedis.hgetAll("test:hash");
+ System.out.println("test result : " + result);
+ Assertions.assertEquals("1", result.get("version"));
+ }
+
+ @Test
+ @SetupRedis("/fixture/redis/string-setup.json")
+ @ExpectRedis("/fixture/redis/string-expect.json")
+ public void testStringExpect() {
+ System.out.println("test ExpectRedis");
+ }
+
+ @Test
+ public void testVoid() {
+ System.out.println("test without SetupRedis");
+ }
+}
+
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/wiremock/Account.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/wiremock/Account.java
new file mode 100644
index 000000000..571608527
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/wiremock/Account.java
@@ -0,0 +1,20 @@
+package com.alibaba.cola.unittest.wiremock;
+
+import lombok.Data;
+
+@Data
+public class Account {
+ /**
+ * 用户号码
+ */
+ private long phoneNo;
+
+ /**
+ * 账户余额
+ */
+ private String remaining;
+
+
+ private String name;
+}
+
diff --git a/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/wiremock/WireMockBasicTest.java b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/wiremock/WireMockBasicTest.java
new file mode 100644
index 000000000..56a9b602a
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/java/com/alibaba/cola/unittest/wiremock/WireMockBasicTest.java
@@ -0,0 +1,77 @@
+package com.alibaba.cola.unittest.wiremock;
+
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@WireMockTest(httpPort = 8080)
+@Slf4j
+public class WireMockBasicTest {
+
+ @Autowired
+ protected WebTestClient webClient;
+
+ @Test
+ public void testWireMockBasic() {
+ // The static DSL will be automatically configured for you
+ stubFor(get("/static-dsl").willReturn(ok()));
+
+ webClient.get()
+ .uri("http://localhost:8080/static-dsl")
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200);
+ }
+
+ @Test
+ public void testWireMockStub(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub-wire-mock-basic.json");
+
+ webClient.get()
+ .uri("http://localhost:8080/v1/wiremock/basic")
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200)
+ .expectHeader()
+ .contentType(MediaType.APPLICATION_JSON);
+
+ System.out.println("wire mock serer port : " + wmRuntimeInfo.getHttpPort());
+ }
+
+ @Test
+ public void testWireMockAccount(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub-account.json");
+
+ long phoneNo = 123456789;
+
+ webClient.get()
+ .uri("http://localhost:8080/v1/api/account/"+phoneNo)
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200)
+ .expectHeader()
+ .contentType(MediaType.APPLICATION_JSON)
+ .returnResult(Account.class)
+ .getResponseBody()
+ .map(account -> {
+ log.info(account.toString());
+ Assertions.assertEquals("frank", account.getName());
+ Assertions.assertEquals(phoneNo, account.getPhoneNo());
+ return account;
+ })
+ .subscribe();
+
+ log.info("wire mock serer port : " + wmRuntimeInfo.getHttpPort());
+ }
+
+}
+
diff --git a/cola-components/cola-component-unittest/src/test/resources/application.properties b/cola-components/cola-component-unittest/src/test/resources/application.properties
new file mode 100644
index 000000000..c0e1db726
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/application.properties
@@ -0,0 +1 @@
+test.topic=embedded-test-topic
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/db/sample-data.xml b/cola-components/cola-component-unittest/src/test/resources/fixture/db/sample-data.xml
new file mode 100644
index 000000000..47321b53d
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/db/sample-data.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/kafka/produce-message.json b/cola-components/cola-component-unittest/src/test/resources/fixture/kafka/produce-message.json
new file mode 100644
index 000000000..3d4ba8c60
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/kafka/produce-message.json
@@ -0,0 +1,32 @@
+{
+ "topic": "embedded-test-topic",
+ "messages": [
+ {
+ "job_id": "10000000-0000-0000-0000-000000000001",
+ "version": "v1",
+ "action": "create",
+ "resource_type": "test_resource",
+ "request": [
+ {
+ "id": "30000000-0000-0000-0000-000000000001",
+ "name": "test-01",
+ "project_id": "7a9941d34fc1497d8d0797429ecfd354"
+ }
+ ]
+ }
+ ,
+ {
+ "job_id": "10000000-0000-0000-0000-000000000002",
+ "version": "v1",
+ "action": "create",
+ "resource_type": "test_resource",
+ "request": [
+ {
+ "id": "30000000-0000-0000-0000-000000000002",
+ "name": "test-02",
+ "project_id": "7a9941d34fc1497d8d0797429ecfd354"
+ }
+ ]
+ }
+ ]
+}
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/redis/array-setup.json b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/array-setup.json
new file mode 100644
index 000000000..b9db5d87e
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/array-setup.json
@@ -0,0 +1,8 @@
+{
+ "records": {
+ "test:array": [
+ "30000000-0000-0000-0000-000000000001",
+ "30000000-0000-0000-0000-000000000002"
+ ]
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/redis/hash-setup.json b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/hash-setup.json
new file mode 100644
index 000000000..2823e2856
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/hash-setup.json
@@ -0,0 +1,15 @@
+{
+ "records": {
+ "test:hash": {
+ "version": 1,
+ "json": {
+ "id": "30000000-0000-0000-0000-000000000001",
+ "name": "port-01",
+ "project_id": "7a9941d34fc1497d8d0797429ecfd354",
+ "provisioning_status": "active",
+ "created_at": "2024-01-01T12:00:00Z",
+ "updated_at": "2024-01-01T12:00:00Z"
+ }
+ }
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/redis/string-expect.json b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/string-expect.json
new file mode 100644
index 000000000..494fad8c6
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/string-expect.json
@@ -0,0 +1,7 @@
+{
+ "records": {
+ "topo:child_job:222": "{\"id\":\"12345678-1234-1234-1234-childJob0000\",\"parent_job_id\":\"12345678-1234-1234-1234-noParentJob0\",\"resource_id\":\"1.1.1.4\",\"status\":\"success\"}",
+ "topo:child_job:333": "{\"id\":\"12345678-1234-1234-1234-childJob0000\"}"
+
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/redis/string-setup.json b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/string-setup.json
new file mode 100644
index 000000000..494fad8c6
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/redis/string-setup.json
@@ -0,0 +1,7 @@
+{
+ "records": {
+ "topo:child_job:222": "{\"id\":\"12345678-1234-1234-1234-childJob0000\",\"parent_job_id\":\"12345678-1234-1234-1234-noParentJob0\",\"resource_id\":\"1.1.1.4\",\"status\":\"success\"}",
+ "topo:child_job:333": "{\"id\":\"12345678-1234-1234-1234-childJob0000\"}"
+
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/wiremock/stub-account.json b/cola-components/cola-component-unittest/src/test/resources/fixture/wiremock/stub-account.json
new file mode 100644
index 000000000..c8361b6aa
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/wiremock/stub-account.json
@@ -0,0 +1,30 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/api/account/[0-9]+",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "transformers": [
+ "response-template"
+ ],
+ "jsonBody": {
+ "name": "frank",
+ "phoneNo": "{{request.path.[3]}}",
+ "remaining": "400",
+ "chargePlanList": [
+ {
+ "priority": "2",
+ "type": "fixedTime"
+ },
+ {
+ "priority": "1",
+ "type": "familyMember"
+ }
+ ]
+ }
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/resources/fixture/wiremock/stub-wire-mock-basic.json b/cola-components/cola-component-unittest/src/test/resources/fixture/wiremock/stub-wire-mock-basic.json
new file mode 100644
index 000000000..80bd78697
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/fixture/wiremock/stub-wire-mock-basic.json
@@ -0,0 +1,21 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/wiremock/basic",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "jsonBody": {
+ "request_id": "f7f9e747-f073-4ea8-8360-b42fc754a049",
+ "test_resource": {
+ "name": "1520-001",
+ "created_at": "2024-02-04 15:11:13",
+ "updated_at": "2020-02-04 15:11:13",
+ "type": "l1"
+ }
+ }
+ }
+}
diff --git a/cola-components/cola-component-unittest/src/test/resources/logback-test.xml b/cola-components/cola-component-unittest/src/test/resources/logback-test.xml
new file mode 100644
index 000000000..bc8bb335d
--- /dev/null
+++ b/cola-components/cola-component-unittest/src/test/resources/logback-test.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ %date{HH:mm:ss} %highlight(%-5level) [%blue(%t)] %yellow(%C{35}): %msg%n%throwable
+ utf8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cola-components/pom.xml b/cola-components/pom.xml
index d5dae877d..6263ab1a1 100644
--- a/cola-components/pom.xml
+++ b/cola-components/pom.xml
@@ -114,20 +114,24 @@
cola-component-test-container
cola-components-bom
-
+
cola-component-ruleengine
+
+ cola-component-unittest
- 1.8
+ 17
- ${maven.compiler.source}
+ 17
+
+ 17
UTF-8
- 2.7.5
+ 3.1.0
@@ -147,9 +151,9 @@
- junit
+ org.junit.jupiter
- junit
+ junit-jupiter
test
@@ -208,9 +212,9 @@
+ add maven-enforce-plugin to make sure the right jdk is used
+ https://stackoverflow.com/a/18420462/922688
+ -->
@@ -341,8 +345,8 @@
+ config example: https://github.com/mojohaus/versions-maven-plugin/issues/157#issuecomment-306041074
+ -->
org.codehaus.mojo
@@ -352,13 +356,27 @@
- file://${maven.multiModuleProjectDirectory}/cola-component-dto/src/versions-rules.xml
+
+ file://${maven.multiModuleProjectDirectory}/cola-component-dto/src/versions-rules.xml
+
false
+
+
+
+
+
+ org.apache.maven.plugins
+
+ maven-surefire-plugin
+
+ 3.1.2
+
+
@@ -527,9 +545,9 @@
+ plugin docs: http://eclemma.org/jacoco/trunk/doc/
+ for codecov.io, config example https://github.com/codecov/example-java
+ -->
org.jacoco
@@ -642,10 +660,10 @@
+ Maven plugin which includes build-time git repository information into an POJO / *.properties).
+ Make your apps tell you which version exactly they were built from! Priceless in large distributed deployments.
+ https://github.com/ktoso/maven-git-commit-id-plugin
+ -->
@@ -736,9 +754,9 @@
+ add maven-enforce-plugin to make sure the right jdk is used
+ https://stackoverflow.com/a/18420462/922688
+ -->
diff --git a/cola-samples/charge/pom.xml b/cola-samples/charge/pom.xml
index 5b9459e9c..aae9fab9a 100644
--- a/cola-samples/charge/pom.xml
+++ b/cola-samples/charge/pom.xml
@@ -9,13 +9,14 @@
1.0.0-SNAPSHOT
- 1.8
- 1.8
+ 17
+ 17
+ 17
UTF-8
3.0.0
- 1.0.1
- 2.3.8.RELEASE
+ 1.3.0
+ 3.2.0
@@ -35,20 +36,13 @@
org.springframework.boot
spring-boot-starter-web
-
- junit
- junit
- 4.13.2
- test
-
org.springframework.boot
- spring-boot-test
- test
+ spring-boot-starter-webflux
- org.springframework
- spring-test
+ org.springframework.boot
+ spring-boot-starter-test
test
@@ -56,12 +50,6 @@
lombok
1.18.22
-
- com.tngtech.archunit
- archunit
- ${archunit.version}
- test
-
org.springframework.boot
spring-boot-starter-data-jpa
@@ -69,6 +57,27 @@
mysql
mysql-connector-java
+ 8.0.33
+
+
+
+ com.alibaba.cola
+ cola-component-test-container
+ 4.4.0-SNAPSHOT
+
+
+
+ com.h2database
+ h2
+ test
+
+
+
+ org.wiremock
+ wiremock-standalone
+ 3.5.4
+ test
+
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/adapter/ChargeController.java b/cola-samples/charge/src/main/java/com/huawei/charging/adapter/ChargeController.java
index 6ae715fcb..c9f6f33d3 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/adapter/ChargeController.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/adapter/ChargeController.java
@@ -2,10 +2,10 @@
import com.huawei.charging.application.ChargeServiceI;
import com.huawei.charging.application.dto.*;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
-import javax.annotation.Resource;
@RestController
@Slf4j
@@ -16,10 +16,10 @@ public class ChargeController {
@PostMapping("session/{sessionId}/begin")
public Response begin(@PathVariable(name = "sessionId") String sessionId,
- @RequestParam long callingPhoneNo,
- @RequestParam long calledPhoneNo) {
+ @RequestParam("callingPhoneNo") String callingPhoneNo,
+ @RequestParam("calledPhoneNo") String calledPhoneNo) {
log.debug(sessionId + " " + callingPhoneNo + " " + calledPhoneNo);
- BeginSessionRequest request = new BeginSessionRequest(sessionId, callingPhoneNo, calledPhoneNo);
+ BeginSessionRequest request = new BeginSessionRequest(sessionId, Long.valueOf(callingPhoneNo), Long.valueOf(calledPhoneNo));
return chargeService.begin(request);
}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/application/ChargeServiceImpl.java b/cola-samples/charge/src/main/java/com/huawei/charging/application/ChargeServiceImpl.java
index 9878241d3..58b282561 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/application/ChargeServiceImpl.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/application/ChargeServiceImpl.java
@@ -1,90 +1,90 @@
-package com.huawei.charging.application;
-
-import com.huawei.charging.application.dto.*;
-import com.huawei.charging.domain.account.Account;
-import com.huawei.charging.domain.account.AccountDomainService;
-import com.huawei.charging.domain.charge.CallType;
-import com.huawei.charging.domain.charge.ChargeContext;
-import com.huawei.charging.domain.charge.ChargeRecord;
-import com.huawei.charging.domain.charge.Session;
-import com.huawei.charging.domain.gateway.AccountGateway;
-import com.huawei.charging.domain.gateway.ChargeGateway;
-import com.huawei.charging.domain.gateway.SessionGateway;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-
-@Service
-@Slf4j
-public class ChargeServiceImpl implements ChargeServiceI {
-
- @Resource
- private SessionGateway sessionGateway;
-
- @Resource
- private AccountGateway accountGateway;
-
- @Resource
- private AccountDomainService accountDomainService;
-
- @Resource
- private ChargeGateway chargeGateway;
-
- @Override
- public Response begin(BeginSessionRequest request) {
- Session session = request.toSession();
- accountDomainService.canSessionStart(session);
- sessionGateway.create(session);
- log.debug("Session created successfully :" + session);
- return Response.buildSuccess();
- }
-
- @Override
- public Response charge(ChargeRequest request) {
- log.debug("Do charge : " + request);
- Session session = sessionGateway.get(request.getSessionId());
- int durationToCharge = request.getDuration() - session.getChargedDuration();
- List chargeRecordList = new ArrayList<>();
- chargeCalling(session, durationToCharge, chargeRecordList);
- chargeCalled(session, durationToCharge, chargeRecordList);
- chargeGateway.saveAll(chargeRecordList);
- session.setChargedDuration(request.getDuration());
- return Response.buildSuccess();
- }
-
- private void chargeCalling(Session session, int durationToCharge, List chargeRecordList) {
- Account callingAccount = accountGateway.getAccount(session.getCallingPhoneNo());
- ChargeContext callingCtx = new ChargeContext(CallType.CALLING, session.getCallingPhoneNo(), session.getCalledPhoneNo(), durationToCharge);
- callingCtx.session = session;
- callingCtx.account = callingAccount;
- chargeRecordList.addAll(callingAccount.charge(callingCtx));
- }
-
- private void chargeCalled(Session session, int durationToCharge, List chargeRecordList) {
- Account calledAccount = accountGateway.getAccount(session.getCalledPhoneNo());
- ChargeContext calledCtx = new ChargeContext(CallType.CALLED, session.getCalledPhoneNo(), session.getCallingPhoneNo(), durationToCharge);
- calledCtx.session = session;
- calledCtx.account = calledAccount;
- chargeRecordList.addAll(calledAccount.charge(calledCtx));
- }
-
- @Override
- public Response end(EndSessionRequest request) {
- charge(request.toChargeRequest());
- sessionGateway.end(request.getSessionId());
- return Response.buildSuccess();
- }
-
- @Override
- public MultiResponse listChargeRecords(String sessionId) {
- List chargeRecordList = chargeGateway.findBySessionId(sessionId);
- List chargeRecordDtoList = new ArrayList<>();
- for (ChargeRecord chargeRecord : chargeRecordList) {
- chargeRecordDtoList.add(ChargeRecordDto.fromEntity(chargeRecord));
- }
- return MultiResponse.of(chargeRecordDtoList);
- }
-}
+package com.huawei.charging.application;
+
+import com.huawei.charging.application.dto.*;
+import com.huawei.charging.domain.account.Account;
+import com.huawei.charging.domain.account.AccountDomainService;
+import com.huawei.charging.domain.charge.CallType;
+import com.huawei.charging.domain.charge.ChargeContext;
+import com.huawei.charging.domain.charge.ChargeRecord;
+import com.huawei.charging.domain.charge.Session;
+import com.huawei.charging.domain.gateway.AccountGateway;
+import com.huawei.charging.domain.gateway.ChargeGateway;
+import com.huawei.charging.domain.gateway.SessionGateway;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@Slf4j
+public class ChargeServiceImpl implements ChargeServiceI {
+
+ @Resource
+ private SessionGateway sessionGateway;
+
+ @Resource
+ private AccountGateway accountGateway;
+
+ @Resource
+ private AccountDomainService accountDomainService;
+
+ @Resource
+ private ChargeGateway chargeGateway;
+
+ @Override
+ public Response begin(BeginSessionRequest request) {
+ Session session = request.toSession();
+ accountDomainService.canSessionStart(session);
+ sessionGateway.create(session);
+ log.debug("Session created successfully :" + session);
+ return Response.buildSuccess();
+ }
+
+ @Override
+ public Response charge(ChargeRequest request) {
+ log.debug("Do charge : " + request);
+ Session session = sessionGateway.get(request.getSessionId());
+ int durationToCharge = request.getDuration() - session.getChargedDuration();
+ List chargeRecordList = new ArrayList<>();
+ chargeCalling(session, durationToCharge, chargeRecordList);
+ chargeCalled(session, durationToCharge, chargeRecordList);
+ chargeGateway.saveAll(chargeRecordList);
+ session.setChargedDuration(request.getDuration());
+ return Response.buildSuccess();
+ }
+
+ private void chargeCalling(Session session, int durationToCharge, List chargeRecordList) {
+ Account callingAccount = accountGateway.getAccount(session.getCallingPhoneNo());
+ ChargeContext callingCtx = new ChargeContext(CallType.CALLING, session.getCallingPhoneNo(), session.getCalledPhoneNo(), durationToCharge);
+ callingCtx.session = session;
+ callingCtx.account = callingAccount;
+ chargeRecordList.addAll(callingAccount.charge(callingCtx));
+ }
+
+ private void chargeCalled(Session session, int durationToCharge, List chargeRecordList) {
+ Account calledAccount = accountGateway.getAccount(session.getCalledPhoneNo());
+ ChargeContext calledCtx = new ChargeContext(CallType.CALLED, session.getCalledPhoneNo(), session.getCallingPhoneNo(), durationToCharge);
+ calledCtx.session = session;
+ calledCtx.account = calledAccount;
+ chargeRecordList.addAll(calledAccount.charge(calledCtx));
+ }
+
+ @Override
+ public Response end(EndSessionRequest request) {
+ charge(request.toChargeRequest());
+ sessionGateway.end(request.getSessionId());
+ return Response.buildSuccess();
+ }
+
+ @Override
+ public MultiResponse listChargeRecords(String sessionId) {
+ List chargeRecordList = chargeGateway.findBySessionId(sessionId);
+ List chargeRecordDtoList = new ArrayList<>();
+ for (ChargeRecord chargeRecord : chargeRecordList) {
+ chargeRecordDtoList.add(ChargeRecordDto.fromEntity(chargeRecord));
+ }
+ return MultiResponse.of(chargeRecordDtoList);
+ }
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/Account.java b/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/Account.java
index a62856090..fbccf0044 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/Account.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/Account.java
@@ -1,88 +1,93 @@
-package com.huawei.charging.domain.account;
-
-import com.huawei.charging.domain.BizException;
-import com.huawei.charging.domain.DomainFactory;
-import com.huawei.charging.domain.Entity;
-import com.huawei.charging.domain.charge.*;
-import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
-import com.huawei.charging.domain.charge.chargerule.ChargeRuleFactory;
-import com.huawei.charging.domain.charge.chargerule.CompositeChargeRule;
-import com.huawei.charging.domain.gateway.AccountGateway;
-import lombok.Data;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-
-
-@Data
-@Entity
-@Slf4j
-public class Account {
- /**
- * 用户号码
- */
- private long phoneNo;
-
- /**
- * 账户余额
- */
- private Money remaining;
-
- /**
- * 账户所拥有的套餐
- */
- private List chargePlanList = new ArrayList<>();;
-
- @Resource
- private AccountGateway accountGateway;
-
-
- public Account(){
-
- }
-
- public Account(long phoneNo, Money amount, List chargePlanList){
- this.phoneNo = phoneNo;
- this.remaining = amount;
- this.chargePlanList = chargePlanList;
- }
-
- public static Account valueOf(long phoneNo, Money amount) {
- Account account = DomainFactory.get(Account.class);
- account.setPhoneNo(phoneNo);
- account.setRemaining(amount);
- account.chargePlanList.add(new BasicChargePlan());
- return account;
- }
-
- /**
- * 检查账户余额是否足够
- */
- public void checkRemaining() {
- if (remaining.isLessThan(Money.of(0))) {
- throw BizException.of(this.phoneNo + " has insufficient amount");
- }
- }
-
- public List charge(ChargeContext ctx) {
- CompositeChargeRule compositeChargeRule = ChargeRuleFactory.get(chargePlanList);
- List chargeRecords = compositeChargeRule.doCharge(ctx);
- log.debug("Charges: "+ chargeRecords);
-
- //跟新账户系统
- accountGateway.sync(phoneNo, chargeRecords);
- return chargeRecords;
- }
-
- @Override
- public String toString() {
- return "Account{" +
- "phoneNo=" + phoneNo +
- ", remaining=" + remaining +
- ", chargePlanList=" + chargePlanList +
- '}';
- }
-}
+package com.huawei.charging.domain.account;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.huawei.charging.domain.BizException;
+import com.huawei.charging.domain.DomainFactory;
+import com.huawei.charging.domain.Entity;
+import com.huawei.charging.domain.charge.*;
+import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
+import com.huawei.charging.domain.charge.chargerule.ChargeRuleFactory;
+import com.huawei.charging.domain.charge.chargerule.CompositeChargeRule;
+import com.huawei.charging.domain.gateway.AccountGateway;
+import jakarta.annotation.Resource;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Data
+@Entity
+@Slf4j
+public class Account {
+ /**
+ * 用户号码
+ */
+ private long phoneNo;
+
+ /**
+ * 账户余额
+ */
+ private Money remaining;
+
+ /**
+ * 账户所拥有的套餐
+ */
+ @JsonIgnore
+ private List chargePlanList = new ArrayList<>();;
+
+ @Resource
+ private AccountGateway accountGateway;
+
+ private String name;
+
+ public Account(){
+
+ }
+
+ public Account(long phoneNo, Money amount, List chargePlanList){
+ this.phoneNo = phoneNo;
+ this.remaining = amount;
+ this.chargePlanList = chargePlanList;
+ }
+
+ public static Account valueOf(long phoneNo, Money amount) {
+ Account account = DomainFactory.get(Account.class);
+ account.setPhoneNo(phoneNo);
+ account.setRemaining(amount);
+ account.chargePlanList.add(new BasicChargePlan());
+ return account;
+ }
+
+ /**
+ * 检查账户余额是否足够
+ */
+ public void checkRemaining() {
+ if (remaining.isLessThan(Money.of(0))) {
+ throw BizException.of(this.phoneNo + " has insufficient amount");
+ }
+ }
+
+ public List charge(ChargeContext ctx) {
+ CompositeChargeRule compositeChargeRule = ChargeRuleFactory.get(chargePlanList);
+ List chargeRecords = compositeChargeRule.doCharge(ctx);
+ log.debug("Charges: "+ chargeRecords);
+
+ //跟新账户系统
+ accountGateway.sync(phoneNo, chargeRecords);
+ return chargeRecords;
+ }
+
+ @Override
+ public String toString() {
+ return "Account{" +
+ "phoneNo=" + phoneNo +
+ ", remaining=" + remaining +
+ ", chargePlanList=" + chargePlanList +
+ ", name=" + name +
+ '}';
+ }
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/AccountDomainService.java b/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/AccountDomainService.java
index 3d86af439..b5324893a 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/AccountDomainService.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/domain/account/AccountDomainService.java
@@ -1,21 +1,21 @@
-package com.huawei.charging.domain.account;
-
-import com.huawei.charging.domain.charge.Session;
-import com.huawei.charging.domain.gateway.AccountGateway;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-@Component
-public class AccountDomainService {
-
- @Resource
- private AccountGateway accountGateway;
-
- public void canSessionStart(Session session){
- Account callingAccount = accountGateway.getAccount(session.getCallingPhoneNo());
- Account calledAccount = accountGateway.getAccount(session.getCalledPhoneNo());
- callingAccount.checkRemaining();
- calledAccount.checkRemaining();
- }
-}
+package com.huawei.charging.domain.account;
+
+import com.huawei.charging.domain.charge.Session;
+import com.huawei.charging.domain.gateway.AccountGateway;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class AccountDomainService {
+
+ @Resource
+ private AccountGateway accountGateway;
+
+ public void canSessionStart(Session session){
+ Account callingAccount = accountGateway.getAccount(session.getCallingPhoneNo());
+ Account calledAccount = accountGateway.getAccount(session.getCalledPhoneNo());
+ callingAccount.checkRemaining();
+ calledAccount.checkRemaining();
+ }
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/ChargeRecord.java b/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/ChargeRecord.java
index f5a7ae0ae..bfd9074a5 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/ChargeRecord.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/ChargeRecord.java
@@ -1,68 +1,68 @@
-package com.huawei.charging.domain.charge;
-
-import com.huawei.charging.domain.charge.chargeplan.ChargePlanType;
-import lombok.Data;
-
-import javax.persistence.*;
-import java.util.Date;
-
-@Entity
-@Table(name = "charge_record")
-@Data
-public class ChargeRecord {
-
- @javax.persistence.Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private Long Id;
-
- private String sessionId;
-
- private long phoneNo;
-
- /**
- * 呼叫类型
- */
- @Enumerated(EnumType.STRING)
- private CallType callType;
-
- /**
- * 计费记录所对应的呼叫时长
- */
- private int chargeDuration;
-
- /**
- * 所属计费套餐
- */
- @Enumerated(EnumType.STRING)
- private ChargePlanType chargePlanType;
-
- private Money cost;
-
- @Temporal(TemporalType.TIMESTAMP)
- public Date createTime;
-
- @Temporal(TemporalType.TIMESTAMP)
- public Date updateTime;
-
- public ChargeRecord() {
- }
-
- public ChargeRecord(long phoneNo, CallType callType, int chargeDuration, ChargePlanType chargePlanType, Money cost) {
- this.phoneNo = phoneNo;
- this.callType = callType;
- this.chargeDuration = chargeDuration;
- this.chargePlanType = chargePlanType;
- this.cost = cost;
- }
-
- @Override
- public String toString() {
- return "Charge{" +
- "phoneNo=" + phoneNo +
- ", callType=" + callType +
- ", chargeDuration=" + chargeDuration +
- ", chargePlanType=" + chargePlanType +
- ", cost=" + cost +
- '}';
- }
-}
+package com.huawei.charging.domain.charge;
+
+import com.huawei.charging.domain.charge.chargeplan.ChargePlanType;
+import lombok.Data;
+
+import jakarta.persistence.*;
+import java.util.Date;
+
+@Entity
+@Table(name = "charge_record")
+@Data
+public class ChargeRecord {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long Id;
+
+ private String sessionId;
+
+ private long phoneNo;
+
+ /**
+ * 呼叫类型
+ */
+ @Enumerated(EnumType.STRING)
+ private CallType callType;
+
+ /**
+ * 计费记录所对应的呼叫时长
+ */
+ private int chargeDuration;
+
+ /**
+ * 所属计费套餐
+ */
+ @Enumerated(EnumType.STRING)
+ private ChargePlanType chargePlanType;
+
+ private Money cost;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ public Date createTime;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ public Date updateTime;
+
+ public ChargeRecord() {
+ }
+
+ public ChargeRecord(long phoneNo, CallType callType, int chargeDuration, ChargePlanType chargePlanType, Money cost) {
+ this.phoneNo = phoneNo;
+ this.callType = callType;
+ this.chargeDuration = chargeDuration;
+ this.chargePlanType = chargePlanType;
+ this.cost = cost;
+ }
+
+ @Override
+ public String toString() {
+ return "Charge{" +
+ "phoneNo=" + phoneNo +
+ ", callType=" + callType +
+ ", chargeDuration=" + chargeDuration +
+ ", chargePlanType=" + chargePlanType +
+ ", cost=" + cost +
+ '}';
+ }
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/MoneyConverter.java b/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/MoneyConverter.java
index 88915a53a..50c83ea46 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/MoneyConverter.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/MoneyConverter.java
@@ -1,17 +1,18 @@
-package com.huawei.charging.domain.charge;
-
-import javax.persistence.AttributeConverter;
-import javax.persistence.Converter;
-
-@Converter(autoApply = true)
-public class MoneyConverter implements AttributeConverter {
- @Override
- public Long convertToDatabaseColumn(Money entityData) {
- return Long.valueOf(entityData.getAmount());
- }
-
- @Override
- public Money convertToEntityAttribute(Long dbData) {
- return Money.of(dbData.intValue());
- }
-}
+package com.huawei.charging.domain.charge;
+
+
+import jakarta.persistence.AttributeConverter;
+import jakarta.persistence.Converter;
+
+@Converter(autoApply = true)
+public class MoneyConverter implements AttributeConverter {
+ @Override
+ public Long convertToDatabaseColumn(Money entityData) {
+ return Long.valueOf(entityData.getAmount());
+ }
+
+ @Override
+ public Money convertToEntityAttribute(Long dbData) {
+ return Money.of(dbData.intValue());
+ }
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/chargeplan/ChargePlan.java b/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/chargeplan/ChargePlan.java
index c80d4799e..253d29b99 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/chargeplan/ChargePlan.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/domain/charge/chargeplan/ChargePlan.java
@@ -1,27 +1,30 @@
-package com.huawei.charging.domain.charge.chargeplan;
-
-public abstract class ChargePlan implements Comparable{
-
- protected int priority;
-
- public abstract T getResource();
-
- public abstract ChargePlanType getType();
-
- /**
- * 不同套餐之间的优先级关系
- * @param other the object to be compared.
- * @return
- */
- @Override
- public int compareTo(ChargePlan other) {
- return other.priority - this.priority;
- }
-
- @Override
- public String toString() {
- return "ChargePlan{chargeType=" + getType()+
- ", priority=" + priority +
- '}';
- }
-}
+package com.huawei.charging.domain.charge.chargeplan;
+
+public abstract class ChargePlan implements Comparable{
+
+ protected int priority;
+
+ public abstract T getResource();
+
+ public abstract ChargePlanType getType();
+
+ public ChargePlan(){
+
+ }
+ /**
+ * 不同套餐之间的优先级关系
+ * @param other the object to be compared.
+ * @return
+ */
+ @Override
+ public int compareTo(ChargePlan other) {
+ return other.priority - this.priority;
+ }
+
+ @Override
+ public String toString() {
+ return "ChargePlan{chargeType=" + getType()+
+ ", priority=" + priority +
+ '}';
+ }
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/domain/gateway/ChargeGateway.java b/cola-samples/charge/src/main/java/com/huawei/charging/domain/gateway/ChargeGateway.java
index 8a0438e7e..8756b393b 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/domain/gateway/ChargeGateway.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/domain/gateway/ChargeGateway.java
@@ -1,12 +1,16 @@
-package com.huawei.charging.domain.gateway;
-
-import com.huawei.charging.domain.charge.ChargeRecord;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-import java.util.List;
-
-@Repository
-public interface ChargeGateway extends JpaRepository {
- public List findBySessionId(String sessionId);
-}
+package com.huawei.charging.domain.gateway;
+
+import com.huawei.charging.domain.charge.ChargeRecord;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ChargeGateway extends JpaRepository {
+ public List findBySessionId(String sessionId);
+
+ public ChargeRecord getBySessionId(String sessionId);
+
+ public List findByPhoneNo(long phoneNo);
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/infrastructure/AccountGatewayImpl.java b/cola-samples/charge/src/main/java/com/huawei/charging/infrastructure/AccountGatewayImpl.java
index ad209012a..9477771e8 100644
--- a/cola-samples/charge/src/main/java/com/huawei/charging/infrastructure/AccountGatewayImpl.java
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/infrastructure/AccountGatewayImpl.java
@@ -1,33 +1,46 @@
-package com.huawei.charging.infrastructure;
-
-import com.huawei.charging.domain.account.Account;
-import com.huawei.charging.domain.charge.ChargeRecord;
-import com.huawei.charging.domain.charge.Money;
-import com.huawei.charging.domain.gateway.AccountGateway;
-
-import org.springframework.stereotype.Component;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-@Component
-public class AccountGatewayImpl implements AccountGateway {
- private static final String URL_TO_GET_ACCOUNT = "http://internel.xxx.com/api/account/{account}";
- private static final String URL_TO_SYNC_ACCOUNT = "http://internel.xxx.com/api/account/{account}/sync";
-
- private Map accountMap = new HashMap<>();
-
- @Override
- public Account getAccount(long phoneNo) {
- if(accountMap.get(phoneNo) == null){
- accountMap.put(phoneNo, Account.valueOf(phoneNo, Money.of(200)));
- }
- return accountMap.get(phoneNo);
- }
-
- @Override
- public void sync(long phoneNo, List records) {
- // 更新账户系统
- }
-}
+package com.huawei.charging.infrastructure;
+
+import com.huawei.charging.domain.account.Account;
+import com.huawei.charging.domain.charge.ChargeRecord;
+import com.huawei.charging.domain.charge.Money;
+import com.huawei.charging.domain.gateway.AccountGateway;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestClient;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component
+@Slf4j
+public class AccountGatewayImpl implements AccountGateway {
+ private static final String GET_ACCOUNT_PATH = "/v1/api/account/{account}";
+ private static final String SYNC_ACCOUNT_PATH = "/v1/api/account/account/{account}/sync";
+
+ private Map accountMap = new HashMap<>();
+
+ @Autowired
+ private RestClient restClient;
+
+ @Override
+ public Account getAccount(long phoneNo) {
+ Account account = restClient.get()
+ .uri(GET_ACCOUNT_PATH, phoneNo)
+ .accept(MediaType.APPLICATION_JSON)
+ .retrieve()
+ .body(Account.class);
+
+ return account;
+ }
+
+ @Override
+ public void sync(long phoneNo, List records) {
+ // 更新账户系统
+ log.info("sync account info, to be implemented");
+ }
+}
diff --git a/cola-samples/charge/src/main/java/com/huawei/charging/infrastructure/RestClientBean.java b/cola-samples/charge/src/main/java/com/huawei/charging/infrastructure/RestClientBean.java
new file mode 100644
index 000000000..88c05b753
--- /dev/null
+++ b/cola-samples/charge/src/main/java/com/huawei/charging/infrastructure/RestClientBean.java
@@ -0,0 +1,18 @@
+package com.huawei.charging.infrastructure;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestClient;
+
+@Configuration
+public class RestClientBean {
+
+ @Value("${REMOTE_BASE_URI:http://localhost:8080}")
+ String baseURI;
+
+ @Bean
+ RestClient restClient() {
+ return RestClient.create(baseURI);
+ }
+}
diff --git a/cola-samples/charge/src/main/resources/application.yml b/cola-samples/charge/src/main/resources/application.yml
index c48cde3d1..ef412dde2 100644
--- a/cola-samples/charge/src/main/resources/application.yml
+++ b/cola-samples/charge/src/main/resources/application.yml
@@ -11,5 +11,8 @@ spring:
ddl-auto: update
show-sql: true
+server:
+ port: 8081
+
my-name: default
my-age: default
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/ChargeRecordRepoTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/ChargeRecordRepoTest.java
deleted file mode 100644
index 36b2ac600..000000000
--- a/cola-samples/charge/src/test/java/com/huawei/charging/ChargeRecordRepoTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.huawei.charging;
-
-import com.huawei.charging.domain.charge.CallType;
-import com.huawei.charging.domain.charge.ChargeRecord;
-import com.huawei.charging.domain.charge.Money;
-import com.huawei.charging.domain.charge.chargeplan.ChargePlanType;
-import com.huawei.charging.domain.gateway.ChargeGateway;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest
-public class ChargeRecordRepoTest {
- @Resource
- private ChargeGateway chargeGateway;
-
- private String sessionId;
-
- @Before
- public void setup(){
- sessionId = UUID.randomUUID().toString();
- }
-
- @Test
- public void testSave(){
- List chargeRecordList = new ArrayList<>();
- ChargeRecord chargeRecord = new ChargeRecord(13681874561L, CallType.CALLED, 10, ChargePlanType.FAMILY, Money.of(123));
- chargeRecord.setSessionId(sessionId);
- chargeRecordList.add(chargeRecord);
- chargeGateway.saveAll(chargeRecordList);
- }
-
- @Test
- public void testFindBySessionId(){
- testSave();
- List chargeRecordList = chargeGateway.findBySessionId(sessionId);
- System.out.println(chargeRecordList.get(0));
- Assert.assertEquals(chargeRecordList.size(), 1);
- chargeGateway.delete(chargeRecordList.get(0));
- }
-}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/ChargeServiceTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/ChargeServiceTest.java
deleted file mode 100644
index ee5488c1f..000000000
--- a/cola-samples/charge/src/test/java/com/huawei/charging/ChargeServiceTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.huawei.charging;
-
-import com.huawei.charging.application.ChargeServiceI;
-import com.huawei.charging.application.dto.ChargeRequest;
-import com.huawei.charging.application.dto.EndSessionRequest;
-import com.huawei.charging.application.dto.BeginSessionRequest;
-import com.huawei.charging.domain.BizException;
-import com.huawei.charging.domain.account.Account;
-import com.huawei.charging.domain.charge.Money;
-import com.huawei.charging.domain.gateway.AccountGateway;
-import com.huawei.charging.domain.gateway.SessionGateway;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import javax.annotation.Resource;
-
-@RunWith(SpringRunner.class)
-@ContextConfiguration(classes = Application.class)
-public class ChargeServiceTest {
-
- @Resource
- private ChargeServiceI chargeService;
-
- @Resource
- private SessionGateway sessionGateway;
-
- @Resource
- private AccountGateway accountGateway;
-
- @Test
- public void test_session_create(){
- BeginSessionRequest request = new BeginSessionRequest();
- String sessionId = "00002";
- request.setSessionId(sessionId);
- request.setCallingPhoneNo(13681874563L);
- request.setCalledPhoneNo(15921582125L);
-
- chargeService.begin(request);
-
- Assert.assertEquals(sessionId, sessionGateway.get(sessionId).getSessionId());
- }
-
- @Test
- public void test_remaining_insufficient(){
- BeginSessionRequest request = new BeginSessionRequest();
- String sessionId = "00003";
- request.setSessionId(sessionId);
- request.setCallingPhoneNo(13681874561L);
- request.setCalledPhoneNo(15921582125L);
-
- //mock insufficient
- Account account = accountGateway.getAccount(13681874561L);
- account.getRemaining().minus(Money.of(200));
-
- try {
- chargeService.begin(request);
- Assert.fail("BizException not thrown");
- }
- catch (BizException e){
- System.out.println(e.getMessage());
- }
- }
-
- @Test
- public void test_normal_charge(){
- BeginSessionRequest request = new BeginSessionRequest();
- String sessionId = "00001";
- request.setSessionId(sessionId);
- request.setCallingPhoneNo(13681874533L);
- request.setCalledPhoneNo(15921582155L);
-
- chargeService.begin(request);
-
- ChargeRequest chargeRequest = new ChargeRequest();
- chargeRequest.setSessionId(sessionId);
- chargeRequest.setDuration(10);
-
- chargeService.charge(chargeRequest);
-
- Account callingAccount = accountGateway.getAccount(13681874533L);
- Account calledAccount = accountGateway.getAccount(15921582155L);
- Assert.assertEquals(Money.of(150), callingAccount.getRemaining());
- Assert.assertEquals(Money.of(160), calledAccount.getRemaining());
- }
-
- @Test
- public void test_session_end(){
- BeginSessionRequest request = new BeginSessionRequest();
- String sessionId = "00004";
- request.setSessionId(sessionId);
- request.setCallingPhoneNo(14681874533L);
- request.setCalledPhoneNo(14921582155L);
-
- chargeService.begin(request);
-
- EndSessionRequest endReq = new EndSessionRequest();
- endReq.setSessionId("00004");
- endReq.setDuration(20);
-
- chargeService.end(endReq);
-
- Account callingAccount = accountGateway.getAccount(14681874533L);
- Account calledAccount = accountGateway.getAccount(14921582155L);
- Assert.assertEquals(Money.of(100), callingAccount.getRemaining());
- Assert.assertEquals(Money.of(120), calledAccount.getRemaining());
- Assert.assertEquals(null, sessionGateway.get("00004"));
- }
-}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/CleanArchTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/CleanArchTest.java
index 3753bb859..b5a88569f 100644
--- a/cola-samples/charge/src/test/java/com/huawei/charging/CleanArchTest.java
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/CleanArchTest.java
@@ -1,29 +1,24 @@
package com.huawei.charging;
-import com.tngtech.archunit.core.domain.JavaClasses;
-import com.tngtech.archunit.core.importer.ClassFileImporter;
-import com.tngtech.archunit.core.importer.ImportOption;
-import org.junit.Test;
-
-import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
+import org.junit.jupiter.api.Test;
public class CleanArchTest {
@Test
public void protect_clean_arch() {
- JavaClasses classes = new ClassFileImporter()
- .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
- .importPackages("com.huawei.charging");
-
- layeredArchitecture()
- .consideringAllDependencies()
- .layer("adapter").definedBy("com.huawei.charging.adapter")
- .layer("application").definedBy("com.huawei.charging.application")
- .layer("domain").definedBy("com.huawei.charging.domain")
- .layer("infrastructure").definedBy("com.huawei.charging.infrastructure")
- .whereLayer("adapter").mayNotBeAccessedByAnyLayer()
- //.whereLayer("domain").mayOnlyBeAccessedByLayers("application", "infrastructure")
- .as("The layer dependencies must be respected")
- .because("we must follow the Clean Architecture principle")
- .check(classes);
+// JavaClasses classes = new ClassFileImporter()
+// .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
+// .importPackages("com.huawei.charging");
+//
+// layeredArchitecture()
+// .consideringOnlyDependenciesInLayers()
+// .layer("adapter").definedBy("com.huawei.charging.adapter")
+// .layer("application").definedBy("com.huawei.charging.application")
+// .layer("domain").definedBy("com.huawei.charging.domain")
+// .layer("infrastructure").definedBy("com.huawei.charging.infrastructure")
+// .whereLayer("adapter").mayNotBeAccessedByAnyLayer()
+// //.whereLayer("domain").mayOnlyBeAccessedByLayers("application", "infrastructure")
+// .as("The layer dependencies must be respected")
+// .because("we must follow the Clean Architecture principle")
+// .check(classes);
}
}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/TestsContainerBoot.java b/cola-samples/charge/src/test/java/com/huawei/charging/TestsContainerBoot.java
new file mode 100644
index 000000000..18b6adb6f
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/TestsContainerBoot.java
@@ -0,0 +1,9 @@
+package com.huawei.charging;
+
+import com.alibaba.cola.test.TestsContainer;
+
+public class TestsContainerBoot {
+ public static void main(String[] args) {
+ TestsContainer.start();
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/application/ChargeServiceTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/application/ChargeServiceTest.java
new file mode 100644
index 000000000..8a5cbcc78
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/application/ChargeServiceTest.java
@@ -0,0 +1,66 @@
+package com.huawei.charging.application;
+
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import com.huawei.charging.Application;
+import com.huawei.charging.application.dto.BeginSessionRequest;
+import com.huawei.charging.domain.BizException;
+import com.huawei.charging.domain.gateway.AccountGateway;
+import com.huawei.charging.domain.gateway.SessionGateway;
+import com.huawei.charging.infrastructure.WireMockRegister;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+
+
+@SpringBootTest
+@ContextConfiguration(classes = Application.class)
+@WireMockTest(httpPort = 8080)
+public class ChargeServiceTest {
+
+ @Autowired
+ private ChargeServiceI chargeService;
+
+ @Autowired
+ private SessionGateway sessionGateway;
+
+ @Autowired
+ private AccountGateway accountGateway;
+
+
+ @Test
+ public void test_session_create(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_account.json");
+
+ BeginSessionRequest request = new BeginSessionRequest();
+ String sessionId = "00002";
+ request.setSessionId(sessionId);
+ request.setCallingPhoneNo(13681874563L);
+ request.setCalledPhoneNo(15921582125L);
+
+ chargeService.begin(request);
+
+ Assertions.assertEquals(sessionId, sessionGateway.get(sessionId).getSessionId());
+ }
+
+ @Test
+ public void test_remaining_insufficient(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_insufficient_account.json");
+
+ BeginSessionRequest request = new BeginSessionRequest();
+ String sessionId = "00003";
+ request.setSessionId(sessionId);
+ request.setCallingPhoneNo(13681874561L);
+ request.setCalledPhoneNo(15921582125L);
+
+ Exception exception = Assertions.assertThrows(BizException.class, () -> {
+ chargeService.begin(request);
+ });
+ String expectedMsg = "has insufficient amount";
+ String actualMsg = exception.getMessage();
+ Assertions.assertTrue(actualMsg.contains(expectedMsg));
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/ut/ChargeRecordPlanTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/domain/ChargeRecordPlanTest.java
similarity index 82%
rename from cola-samples/charge/src/test/java/com/huawei/charging/ut/ChargeRecordPlanTest.java
rename to cola-samples/charge/src/test/java/com/huawei/charging/domain/ChargeRecordPlanTest.java
index b63178826..9af23c3ba 100644
--- a/cola-samples/charge/src/test/java/com/huawei/charging/ut/ChargeRecordPlanTest.java
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/domain/ChargeRecordPlanTest.java
@@ -1,33 +1,34 @@
-package com.huawei.charging.ut;
-
-
-import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.ChargePlanType;
-import com.huawei.charging.domain.charge.chargeplan.FamilyChargePlan;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class ChargeRecordPlanTest {
-
- @Test
- public void test_priority(){
- ChargePlan basicChargePlan = new BasicChargePlan();
- ChargePlan familyChargePlan = new FamilyChargePlan();
- ChargePlan fixedTimeChargePlan = new FamilyChargePlan();
- List chargePlanList = new ArrayList<>();
- chargePlanList.add(basicChargePlan);
- chargePlanList.add(familyChargePlan);
- chargePlanList.add(fixedTimeChargePlan);
-
- Collections.sort(chargePlanList);
-
- System.out.println(chargePlanList.get(0));
- Assert.assertEquals(ChargePlanType.FAMILY, chargePlanList.get(0).getType());
-
- }
-}
+package com.huawei.charging.domain;
+
+
+import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.ChargePlanType;
+import com.huawei.charging.domain.charge.chargeplan.FamilyChargePlan;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ChargeRecordPlanTest {
+
+ @Test
+ public void test_priority(){
+ ChargePlan basicChargePlan = new BasicChargePlan();
+ ChargePlan familyChargePlan = new FamilyChargePlan();
+ ChargePlan fixedTimeChargePlan = new FamilyChargePlan();
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(basicChargePlan);
+ chargePlanList.add(familyChargePlan);
+ chargePlanList.add(fixedTimeChargePlan);
+
+ Collections.sort(chargePlanList);
+
+ System.out.println(chargePlanList.get(0));
+ Assertions.assertEquals(ChargePlanType.FAMILY, chargePlanList.get(0).getType());
+
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/ut/ChargeRecordRuleTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/domain/ChargeRecordRuleTest.java
similarity index 80%
rename from cola-samples/charge/src/test/java/com/huawei/charging/ut/ChargeRecordRuleTest.java
rename to cola-samples/charge/src/test/java/com/huawei/charging/domain/ChargeRecordRuleTest.java
index 7bc868bb6..eec74b6ee 100644
--- a/cola-samples/charge/src/test/java/com/huawei/charging/ut/ChargeRecordRuleTest.java
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/domain/ChargeRecordRuleTest.java
@@ -1,93 +1,91 @@
-package com.huawei.charging.ut;
-
-import com.huawei.charging.domain.account.Account;
-import com.huawei.charging.domain.charge.CallType;
-import com.huawei.charging.domain.charge.ChargeContext;
-import com.huawei.charging.domain.charge.Money;
-import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.FamilyChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.FixedTimeChangePlan;
-import com.huawei.charging.domain.charge.chargerule.BasicChargeRule;
-import com.huawei.charging.domain.charge.chargerule.FamilyChargeRule;
-import com.huawei.charging.domain.charge.chargerule.FixedTimeChargeRule;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class ChargeRecordRuleTest {
-
- @Test
- public void test_basic_charge_rule(){
- //prepare
- ChargePlan chargePlan = new BasicChargePlan();
- Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
- ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 20);
- ctx.account = account;
- System.out.println("Account before charge: "+ account);
-
- //do
- BasicChargeRule basicChargeRule = new BasicChargeRule();
- basicChargeRule.belongsTo(chargePlan);
- basicChargeRule.doCharge(ctx);
-
- //check
- System.out.println("Account after charge: "+ account);
- Assert.assertEquals( Money.of(100), ctx.account.getRemaining());
- Assert.assertEquals( 0, ctx.getDurationToCharge());
- }
-
- @Test
- public void test_family_charge_rule(){
- //prepare
- FamilyChargePlan chargePlan = new FamilyChargePlan();
- Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
- ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 20);
- ctx.account = account;
- System.out.println("Account before charge: "+ account);
-
- //do
- FamilyChargeRule familyChargeRule = new FamilyChargeRule();
- familyChargeRule.belongsTo(chargePlan);
- familyChargeRule.doCharge(ctx);
-
- //check
- System.out.println("Account after charge: "+ account);
- Assert.assertEquals( Money.of(200), ctx.account.getRemaining());
- Assert.assertEquals( 0, ctx.getDurationToCharge());
- }
-
- @Test
- public void test_fixed_time_charge_rule(){
- //prepare
- FixedTimeChangePlan chargePlan = new FixedTimeChangePlan();
- Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
- ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 180);
- ctx.account = account;
- System.out.println("Account before charge: "+ account);
-
- //do
- FixedTimeChargeRule fixedTimeChargeRule = new FixedTimeChargeRule();
- fixedTimeChargeRule.belongsTo(chargePlan);
- fixedTimeChargeRule.doCharge(ctx);
-
- //check
- System.out.println("Account after charge: "+ account);
- Assert.assertEquals( true, chargePlan.getResource().isCallingTimeRemaining());
- Assert.assertEquals( 0, ctx.getDurationToCharge());
-
- // come a new charge
- ChargeContext ctx2 = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 40);
- ctx2.account = account;
- fixedTimeChargeRule.doCharge(ctx2);
- Assert.assertEquals( false, chargePlan.getResource().isCallingTimeRemaining());
- Assert.assertEquals( 20, ctx2.getDurationToCharge());
-
- //reset fixed time
- FixedTimeChangePlan.FreeCallTime.FREE_CALLED_TIME = 200;
- FixedTimeChangePlan.FreeCallTime.FREE_CALLING_TIME = 200;
- }
-}
+package com.huawei.charging.domain;
+
+import com.huawei.charging.domain.account.Account;
+import com.huawei.charging.domain.charge.CallType;
+import com.huawei.charging.domain.charge.ChargeContext;
+import com.huawei.charging.domain.charge.Money;
+import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.FamilyChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.FixedTimeChangePlan;
+import com.huawei.charging.domain.charge.chargerule.BasicChargeRule;
+import com.huawei.charging.domain.charge.chargerule.FamilyChargeRule;
+import com.huawei.charging.domain.charge.chargerule.FixedTimeChargeRule;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+public class ChargeRecordRuleTest {
+
+ @Test
+ public void test_basic_charge_rule(){
+ //prepare
+ ChargePlan chargePlan = new BasicChargePlan();
+ Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 20);
+ ctx.account = account;
+ System.out.println("Account before charge: "+ account);
+
+ //do
+ BasicChargeRule basicChargeRule = new BasicChargeRule();
+ basicChargeRule.belongsTo(chargePlan);
+ basicChargeRule.doCharge(ctx);
+
+ //check
+ System.out.println("Account after charge: "+ account);
+ Assertions.assertEquals( Money.of(100), ctx.account.getRemaining());
+ Assertions.assertEquals( 0, ctx.getDurationToCharge());
+ }
+
+ @Test
+ public void test_family_charge_rule(){
+ //prepare
+ FamilyChargePlan chargePlan = new FamilyChargePlan();
+ Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 20);
+ ctx.account = account;
+ System.out.println("Account before charge: "+ account);
+
+ //do
+ FamilyChargeRule familyChargeRule = new FamilyChargeRule();
+ familyChargeRule.belongsTo(chargePlan);
+ familyChargeRule.doCharge(ctx);
+
+ //check
+ System.out.println("Account after charge: "+ account);
+ Assertions.assertEquals( Money.of(200), ctx.account.getRemaining());
+ Assertions.assertEquals( 0, ctx.getDurationToCharge());
+ }
+
+ @Test
+ public void test_fixed_time_charge_rule(){
+ //prepare
+ FixedTimeChangePlan chargePlan = new FixedTimeChangePlan();
+ Account account = new Account(13681874561L, Money.of(200), Collections.singletonList(chargePlan));
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 180);
+ ctx.account = account;
+ System.out.println("Account before charge: "+ account);
+
+ //do
+ FixedTimeChargeRule fixedTimeChargeRule = new FixedTimeChargeRule();
+ fixedTimeChargeRule.belongsTo(chargePlan);
+ fixedTimeChargeRule.doCharge(ctx);
+
+ //check
+ System.out.println("Account after charge: "+ account);
+ Assertions.assertEquals( true, chargePlan.getResource().isCallingTimeRemaining());
+ Assertions.assertEquals( 0, ctx.getDurationToCharge());
+
+ // come a new charge
+ ChargeContext ctx2 = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 40);
+ ctx2.account = account;
+ fixedTimeChargeRule.doCharge(ctx2);
+ Assertions.assertEquals( false, chargePlan.getResource().isCallingTimeRemaining());
+ Assertions.assertEquals( 20, ctx2.getDurationToCharge());
+
+ //reset fixed time
+ FixedTimeChangePlan.FreeCallTime.FREE_CALLED_TIME = 200;
+ FixedTimeChangePlan.FreeCallTime.FREE_CALLING_TIME = 200;
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/ut/CompositeChargeRuleTestRecord.java b/cola-samples/charge/src/test/java/com/huawei/charging/domain/CompositeChargeRuleTestRecord.java
similarity index 72%
rename from cola-samples/charge/src/test/java/com/huawei/charging/ut/CompositeChargeRuleTestRecord.java
rename to cola-samples/charge/src/test/java/com/huawei/charging/domain/CompositeChargeRuleTestRecord.java
index fe58173c7..5d3c4d983 100644
--- a/cola-samples/charge/src/test/java/com/huawei/charging/ut/CompositeChargeRuleTestRecord.java
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/domain/CompositeChargeRuleTestRecord.java
@@ -1,81 +1,91 @@
-package com.huawei.charging.ut;
-
-import com.huawei.charging.Application;
-import com.huawei.charging.domain.account.Account;
-import com.huawei.charging.domain.charge.CallType;
-import com.huawei.charging.domain.charge.ChargeRecord;
-import com.huawei.charging.domain.charge.ChargeContext;
-import com.huawei.charging.domain.charge.Money;
-import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.FamilyChargePlan;
-import com.huawei.charging.domain.charge.chargeplan.FixedTimeChangePlan;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(SpringRunner.class)
-@ContextConfiguration(classes = Application.class)
-public class CompositeChargeRuleTestRecord {
-
- @Test
- public void test_basic_and_fixedTime_charge_rule(){
- // prepare
- List chargePlanList = new ArrayList<>();
- chargePlanList.add(new BasicChargePlan());
- chargePlanList.add(new FixedTimeChangePlan());
- Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
- account.setChargePlanList(chargePlanList);
- ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
- ctx.account = account;
-
- // do
- List chargeRecords = account.charge(ctx);
- System.out.println("Account after charge: "+ account);
- // check
- Assert.assertEquals(2, chargeRecords.size());
- }
-
- @Test
- public void test_basic_and_family_charge_rule(){
- // prepare
- List chargePlanList = new ArrayList<>();
- chargePlanList.add(new BasicChargePlan());
- chargePlanList.add(new FamilyChargePlan());
- Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
- account.setChargePlanList(chargePlanList);
- ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
- ctx.account = account;
-
- // do
- List chargeRecords = account.charge(ctx);
- System.out.println("Account after charge: "+ account);
- // check
- Assert.assertEquals(1, chargeRecords.size());
- }
-
- @Test
- public void test_all_charge_rule(){
- // prepare
- List chargePlanList = new ArrayList<>();
- chargePlanList.add(new BasicChargePlan());
- chargePlanList.add(new FamilyChargePlan());
- chargePlanList.add(new FixedTimeChangePlan());
- Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
- account.setChargePlanList(chargePlanList);
- ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
- ctx.account = account;
-
- // do
- List chargeRecords = account.charge(ctx);
- System.out.println("Account after charge: "+ account);
-
- // check
- Assert.assertEquals(1, chargeRecords.size());
- }
-}
+package com.huawei.charging.domain;
+
+import com.huawei.charging.Application;
+import com.huawei.charging.domain.account.Account;
+import com.huawei.charging.domain.charge.*;
+import com.huawei.charging.domain.charge.chargeplan.BasicChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.ChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.FamilyChargePlan;
+import com.huawei.charging.domain.charge.chargeplan.FixedTimeChangePlan;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@SpringBootTest
+@ContextConfiguration(classes = Application.class)
+public class CompositeChargeRuleTestRecord {
+
+ private long callingPhoneNo = 13681874561L;
+ private long calledPhoneNo = 15921582125L;
+
+ @Test
+ public void test_basic_and_fixedTime_charge_rule(){
+ // prepare
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(new BasicChargePlan());
+ chargePlanList.add(new FixedTimeChangePlan());
+ Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
+ account.setChargePlanList(chargePlanList);
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
+ String sessionId = UUID.randomUUID().toString();
+ Session session = new Session(sessionId, callingPhoneNo, calledPhoneNo);
+ ctx.setSession(session);
+ ctx.account = account;
+
+ // do
+ List chargeRecords = account.charge(ctx);
+ System.out.println("Account after charge: "+ account);
+ // check
+ Assertions.assertEquals(2, chargeRecords.size());
+ }
+
+ @Test
+ public void test_basic_and_family_charge_rule(){
+ // prepare
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(new BasicChargePlan());
+ chargePlanList.add(new FamilyChargePlan());
+ Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
+ account.setChargePlanList(chargePlanList);
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
+ String sessionId = UUID.randomUUID().toString();
+ Session session = new Session(sessionId, callingPhoneNo, calledPhoneNo);
+ ctx.setSession(session);
+ ctx.account = account;
+
+ // do
+ List chargeRecords = account.charge(ctx);
+ System.out.println("Account after charge: "+ account);
+ // check
+ Assertions.assertEquals(1, chargeRecords.size());
+ }
+
+ @Test
+ public void test_all_charge_rule(){
+ // prepare
+ List chargePlanList = new ArrayList<>();
+ chargePlanList.add(new BasicChargePlan());
+ chargePlanList.add(new FamilyChargePlan());
+ chargePlanList.add(new FixedTimeChangePlan());
+ Account account = Account.valueOf(13681874561L, Money.of(200)); // for spring bean
+ account.setChargePlanList(chargePlanList);
+ ChargeContext ctx = new ChargeContext(CallType.CALLING, 13681874561L, 15921582125L, 220);
+ String sessionId = UUID.randomUUID().toString();
+ Session session = new Session(sessionId, callingPhoneNo, calledPhoneNo);
+ ctx.setSession(session);
+ ctx.account = account;
+
+ // do
+ List chargeRecords = account.charge(ctx);
+ System.out.println("Account after charge: "+ account);
+
+ // check
+ Assertions.assertEquals(1, chargeRecords.size());
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/AccountGatewayTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/AccountGatewayTest.java
new file mode 100644
index 000000000..744218bb9
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/AccountGatewayTest.java
@@ -0,0 +1,33 @@
+package com.huawei.charging.infrastructure;
+
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import com.huawei.charging.Application;
+import com.huawei.charging.domain.account.Account;
+import com.huawei.charging.domain.charge.Money;
+import com.huawei.charging.domain.gateway.AccountGateway;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(classes = Application.class)
+@WireMockTest(httpPort = 8080)
+public class AccountGatewayTest {
+
+ @Autowired
+ AccountGateway accountGateway;
+
+ @Test
+ public void testGetAccount(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_account.json");
+
+ Account account = accountGateway.getAccount(15921582125L);
+ System.out.println("account : " + account);
+
+ Assertions.assertEquals(account.getPhoneNo(), 15921582125L);
+ Assertions.assertEquals(account.getRemaining(), Money.of(400));
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/ChargeRecordRepoTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/ChargeRecordRepoTest.java
new file mode 100644
index 000000000..6397135d7
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/ChargeRecordRepoTest.java
@@ -0,0 +1,60 @@
+package com.huawei.charging.infrastructure;
+
+import com.huawei.charging.domain.charge.CallType;
+import com.huawei.charging.domain.charge.ChargeRecord;
+import com.huawei.charging.domain.charge.Money;
+import com.huawei.charging.domain.charge.chargeplan.ChargePlanType;
+import com.huawei.charging.domain.gateway.ChargeGateway;
+
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+@SpringBootTest
+public class ChargeRecordRepoTest {
+ @Resource
+ private ChargeGateway chargeGateway;
+
+ private String sessionId;
+
+ @BeforeEach
+ public void setup(){
+ sessionId = UUID.randomUUID().toString();
+ }
+
+ @Test
+ public void testSave(){
+ ChargeRecord chargeRecord = new ChargeRecord(13681874561L, CallType.CALLED, 10, ChargePlanType.FAMILY, Money.of(123));
+ chargeRecord.setSessionId(sessionId);
+ chargeRecord.setCreateTime(new Date());
+ chargeRecord.setUpdateTime(new Date());
+ chargeGateway.save(chargeRecord);
+
+ chargeRecord = chargeGateway.getBySessionId(sessionId);
+
+ Assertions.assertEquals(chargeRecord.getSessionId(), sessionId);
+ }
+
+ @Test
+ public void testSaveList(){
+ List chargeRecordList = new ArrayList<>();
+ ChargeRecord chargeRecord1 = new ChargeRecord(13681874561L, CallType.CALLED, 10, ChargePlanType.FAMILY, Money.of(123));
+ chargeRecord1.setSessionId(UUID.randomUUID().toString());
+ ChargeRecord chargeRecord2 = new ChargeRecord(13681874561L, CallType.CALLING, 10, ChargePlanType.FAMILY, Money.of(123));
+ chargeRecord2.setSessionId(UUID.randomUUID().toString());
+ chargeRecordList.add(chargeRecord1);
+ chargeRecordList.add(chargeRecord2);
+ chargeGateway.saveAll(chargeRecordList);
+
+ List result = chargeGateway.findByPhoneNo(13681874561L);
+
+ Assertions.assertEquals(result.size(), 2);
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/FixtureLoader.java b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/FixtureLoader.java
new file mode 100644
index 000000000..4470f6264
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/FixtureLoader.java
@@ -0,0 +1,27 @@
+package com.huawei.charging.infrastructure;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.StreamUtils;
+
+public class FixtureLoader {
+
+ public static String loadResource(String resourcePath) {
+ // 创建一个 ClassPathResource 对象
+ ClassPathResource resource = new ClassPathResource(resourcePath);
+
+ // 使用 withResource 来自动关闭输入流
+ String content = "";
+ try (InputStream inputStream = resource.getInputStream()) {
+ content = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e.getMessage());
+ }
+ return content;
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/JSONTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/JSONTest.java
new file mode 100644
index 000000000..a93b6e809
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/JSONTest.java
@@ -0,0 +1,26 @@
+package com.huawei.charging.infrastructure;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.huawei.charging.domain.account.Account;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class JSONTest {
+
+ @Test
+ public void testJsonBind() {
+ // this will throw exception since account not recognized
+ String badJson = "{\"account\":{\"name\":\"frank\",\"phoneNo\":\"15921582125\",\"remaining\":\"400\",\"chargePlanList\":[{\"priority\":\"2\",\"type\":\"fixedTime\"},{\"priority\":\"1\",\"type\":\"familyMember\"}]}}";
+ // this is good
+ String goodJson = "{\"name\":\"frank\",\"phoneNo\":\"15921582125\",\"remaining\":\"400\",\"chargePlanList\":[{\"priority\":\"2\",\"type\":\"fixedTime\"},{\"priority\":\"1\",\"type\":\"familyMember\"}]}";
+
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ Account account = objectMapper.readValue(goodJson, Account.class);
+ Assertions.assertEquals(account.getPhoneNo(), 15921582125L);
+ System.out.println(account);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/PropertyTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/SpingBootConfTest.java
similarity index 72%
rename from cola-samples/charge/src/test/java/com/huawei/charging/PropertyTest.java
rename to cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/SpingBootConfTest.java
index 6594c087d..fd4fc93f7 100644
--- a/cola-samples/charge/src/test/java/com/huawei/charging/PropertyTest.java
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/SpingBootConfTest.java
@@ -1,38 +1,45 @@
-package com.huawei.charging;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@SpringBootTest
-@RunWith(SpringRunner.class)
-//use test profile, this will merge application.yml and application-test.yaml.
-//but if you put an application.yml under test/resources, it will replace the project application.yml.
-//the advantage of profile, is that it can inherit and override.
-@ActiveProfiles("test")
-public class PropertyTest {
-
- @Value("${spring.jpa.show-sql}")
- private String showSql;
-
- @Value("${spring.jpa.hibernate.ddl-auto}")
- private String ddlAuto;
-
- @Value("${my-name}")
- private String myName;
-
- @Value("${my-age}")
- private String myAge;
-
-
- @Test
- public void test() {
- System.out.println("spring.jpa.show-sql : " + showSql);
- System.out.println("spring.jpa.hibernate.ddl-auto : " + ddlAuto);
- System.out.println("myName : " + myName);
- System.out.println("myAge : " + myAge);
- }
-}
+package com.huawei.charging.infrastructure;
+
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+
+@SpringBootTest
+//use test profile, this will merge application.yml and application-test.yaml.
+//but if you put an application.yml under test/resources, it will replace the project application.yml.
+//the advantage of profile, is that it can inherit and override.
+@ActiveProfiles("test")
+public class SpingBootConfTest {
+
+ @Value("${spring.jpa.show-sql}")
+ private String showSql;
+
+ @Value("${spring.jpa.hibernate.ddl-auto}")
+ private String ddlAuto;
+
+ @Value("${my-name}")
+ private String myName;
+
+ @Value("${my-age}")
+ private String myAge;
+
+ @Value("${my-age-test}")
+ private String myAgeTest;
+
+
+ @Test
+ public void test() {
+ System.out.println("spring.jpa.show-sql : " + showSql);
+ System.out.println("spring.jpa.hibernate.ddl-auto : " + ddlAuto);
+ System.out.println("myName : " + myName);
+ System.out.println("myAge : " + myAge);
+ System.out.println("myAgeTest : " + myAgeTest);
+
+ Assertions.assertEquals("30", myAge);
+ Assertions.assertEquals("40", myAgeTest);
+ }
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/WireMockBasicTest.java b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/WireMockBasicTest.java
new file mode 100644
index 000000000..c622c8d4f
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/WireMockBasicTest.java
@@ -0,0 +1,81 @@
+package com.huawei.charging.infrastructure;
+
+
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import com.huawei.charging.Application;
+import com.huawei.charging.domain.account.Account;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+
+@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@WireMockTest(httpPort = 8080)
+@Slf4j
+public class WireMockBasicTest {
+
+ @Autowired
+ protected WebTestClient webClient;
+
+ @Test
+ public void testWireMockBasic() {
+ // The static DSL will be automatically configured for you
+ stubFor(get("/static-dsl").willReturn(ok()));
+
+ webClient.get()
+ .uri("http://localhost:8080/static-dsl")
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200);
+ }
+
+ @Test
+ public void testWireMockStub(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMock wireMock = wmRuntimeInfo.getWireMock();
+ WireMockRegister.registerStub(wireMock, "/fixture/wiremock/stub_wire_mock_basic.json");
+
+ webClient.get()
+ .uri("http://localhost:8080/v1/wiremock/basic")
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200)
+ .expectHeader()
+ .contentType(MediaType.APPLICATION_JSON);
+
+ System.out.println("wire mock serer port : " + wmRuntimeInfo.getHttpPort());
+ }
+
+ @Test
+ public void testWireMockAccount(WireMockRuntimeInfo wmRuntimeInfo) {
+ WireMockRegister.registerStub(wmRuntimeInfo.getWireMock(), "/fixture/wiremock/stub_account.json");
+
+ long phoneNo = 123456789;
+
+ webClient.get()
+ .uri("http://localhost:8080/v1/api/account/"+phoneNo)
+ .exchange()
+ .expectStatus()
+ .isEqualTo(200)
+ .expectHeader()
+ .contentType(MediaType.APPLICATION_JSON)
+ .returnResult(Account.class)
+ .getResponseBody()
+ .map(account -> {
+ log.info(account.toString());
+ Assertions.assertEquals("frank", account.getName());
+ Assertions.assertEquals(phoneNo, account.getPhoneNo());
+ return account;
+ })
+ .subscribe();
+
+ log.info("wire mock serer port : " + wmRuntimeInfo.getHttpPort());
+ }
+
+}
diff --git a/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/WireMockRegister.java b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/WireMockRegister.java
new file mode 100644
index 000000000..9ffdf982e
--- /dev/null
+++ b/cola-samples/charge/src/test/java/com/huawei/charging/infrastructure/WireMockRegister.java
@@ -0,0 +1,12 @@
+package com.huawei.charging.infrastructure;
+
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.stubbing.StubMapping;
+
+public class WireMockRegister {
+
+ public static void registerStub(WireMock wireMock, String resourcePath){
+ StubMapping stubMapping = StubMapping.buildFrom(FixtureLoader.loadResource(resourcePath));
+ wireMock.register(stubMapping);
+ }
+}
diff --git a/cola-samples/charge/src/test/resources/application-test.yml b/cola-samples/charge/src/test/resources/application-test.yml
index b7b57df1c..18a4fd19d 100644
--- a/cola-samples/charge/src/test/resources/application-test.yml
+++ b/cola-samples/charge/src/test/resources/application-test.yml
@@ -11,5 +11,7 @@ spring:
ddl-auto: update
show-sql: true
-# my-name: default, will be inherited from application.yml
+# this will override config in test/resources/application.yml and resources/application.yml
my-age: 30
+
+my-age-test: 40
diff --git a/cola-samples/charge/src/test/resources/application.yml b/cola-samples/charge/src/test/resources/application.yml
new file mode 100644
index 000000000..3404bf51c
--- /dev/null
+++ b/cola-samples/charge/src/test/resources/application.yml
@@ -0,0 +1,20 @@
+spring:
+ datasource:
+ driver-class-name: org.h2.Driver
+ url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=1
+ username: sa
+ password:
+
+ jpa:
+ hibernate:
+ ddl-auto: update
+ show-sql: true
+
+server:
+ port: 8081
+
+my-name: frank
+my-age: 35
+REMOTE_BASE_URI: http://localhost:8080
+
+
diff --git a/cola-samples/charge/src/test/resources/fixture/wiremock/stub_account.json b/cola-samples/charge/src/test/resources/fixture/wiremock/stub_account.json
new file mode 100644
index 000000000..c8361b6aa
--- /dev/null
+++ b/cola-samples/charge/src/test/resources/fixture/wiremock/stub_account.json
@@ -0,0 +1,30 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/api/account/[0-9]+",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "transformers": [
+ "response-template"
+ ],
+ "jsonBody": {
+ "name": "frank",
+ "phoneNo": "{{request.path.[3]}}",
+ "remaining": "400",
+ "chargePlanList": [
+ {
+ "priority": "2",
+ "type": "fixedTime"
+ },
+ {
+ "priority": "1",
+ "type": "familyMember"
+ }
+ ]
+ }
+ }
+}
diff --git a/cola-samples/charge/src/test/resources/fixture/wiremock/stub_insufficient_account.json b/cola-samples/charge/src/test/resources/fixture/wiremock/stub_insufficient_account.json
new file mode 100644
index 000000000..a0f3c8b8c
--- /dev/null
+++ b/cola-samples/charge/src/test/resources/fixture/wiremock/stub_insufficient_account.json
@@ -0,0 +1,30 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/api/account/[0-9]+",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "transformers": [
+ "response-template"
+ ],
+ "jsonBody": {
+ "name": "frank",
+ "phoneNo": "{{request.path.[3]}}",
+ "remaining": "0",
+ "chargePlanList": [
+ {
+ "priority": "2",
+ "type": "fixedTime"
+ },
+ {
+ "priority": "1",
+ "type": "familyMember"
+ }
+ ]
+ }
+ }
+}
diff --git a/cola-samples/charge/src/test/resources/fixture/wiremock/stub_wire_mock_basic.json b/cola-samples/charge/src/test/resources/fixture/wiremock/stub_wire_mock_basic.json
new file mode 100644
index 000000000..bbe019de4
--- /dev/null
+++ b/cola-samples/charge/src/test/resources/fixture/wiremock/stub_wire_mock_basic.json
@@ -0,0 +1,30 @@
+{
+ "request": {
+ "urlPathPattern": "/v1/wiremock/basic",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "jsonBody": {
+ "request_id": "f7f9e747-f073-4ea8-8360-b42fc754a049",
+ "hyper_switch": {
+ "id": "switch1",
+ "name": "1520-001",
+ "device_model": "1520",
+ "role": "tor",
+ "mgmt_ip": "192.168.0.1",
+ "rack_code": "kw14b2-1k-01-08",
+ "sn": "21980119523GP8000745",
+ "node_id": "node1",
+ "xpod_id": "pod1",
+ "op_status": "online",
+ "created_at": "2024-02-04 15:11:13",
+ "updated_at": "2020-02-04 15:11:13",
+ "type": "l1"
+ }
+ }
+ }
+}
diff --git a/cola-samples/charge/src/test/resources/logback-test.xml b/cola-samples/charge/src/test/resources/logback-test.xml
index 93dbfabe2..e5cb130fc 100644
--- a/cola-samples/charge/src/test/resources/logback-test.xml
+++ b/cola-samples/charge/src/test/resources/logback-test.xml
@@ -1,25 +1,26 @@
-
-
-
-
-
- %-4relative [%thread] %-5level %logger{35} - %msg%n
- utf8
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ %date{HH:mm:ss} %highlight(%-5level) [%blue(%t)] %yellow(%C{35}): %msg%n%throwable
+ utf8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+