This is an automated email from the ASF dual-hosted git repository. ningjiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/servicecomb-pack.git
commit b78efa78608b3d8d5dbbdebb871390ec3a322dce Author: Lei Zhang <[email protected]> AuthorDate: Sat Aug 3 00:08:22 2019 +0800 SCB-1369 Add unit test cases for APIControllerV1 --- .../fsm/repository/model/GlobalTransaction.java | 3 + .../fsm/repository/model/SagaSubTransaction.java | 3 + .../alpha/server/api/APIControllerV1Tests.java | 310 +++++++++++++++++++++ 3 files changed, 316 insertions(+) diff --git a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/GlobalTransaction.java b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/GlobalTransaction.java index 8ec31c4..28b4165 100644 --- a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/GlobalTransaction.java +++ b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/GlobalTransaction.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.pack.alpha.fsm.repository.model; +import com.fasterxml.jackson.annotation.JsonFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; @@ -31,7 +32,9 @@ public class GlobalTransaction { private TransactionType type; private String serviceName; private String instanceId; + @JsonFormat(shape = JsonFormat.Shape.NUMBER) private Date beginTime; + @JsonFormat(shape = JsonFormat.Shape.NUMBER) private Date endTime; private SagaActorState state; private Integer subTxSize; diff --git a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/SagaSubTransaction.java b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/SagaSubTransaction.java index a70585e..0c07f35 100644 --- a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/SagaSubTransaction.java +++ b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/repository/model/SagaSubTransaction.java @@ -17,13 +17,16 @@ package org.apache.servicecomb.pack.alpha.fsm.repository.model; +import com.fasterxml.jackson.annotation.JsonFormat; import java.util.Date; import org.apache.servicecomb.pack.alpha.fsm.TxState; public class SagaSubTransaction { private String localTxId; private String parentTxId; + @JsonFormat(shape = JsonFormat.Shape.NUMBER) private Date beginTime; + @JsonFormat(shape = JsonFormat.Shape.NUMBER) private Date endTime; private TxState state; private Long durationTime; diff --git a/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/api/APIControllerV1Tests.java b/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/api/APIControllerV1Tests.java new file mode 100644 index 0000000..e4914b2 --- /dev/null +++ b/alpha/alpha-server/src/test/java/org/apache/servicecomb/pack/alpha/server/api/APIControllerV1Tests.java @@ -0,0 +1,310 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.pack.alpha.server.api; + +import static org.hamcrest.Matchers.hasSize; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonGenerator.Feature; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import org.apache.servicecomb.pack.alpha.core.NodeStatus; +import org.apache.servicecomb.pack.alpha.core.NodeStatus.TypeEnum; +import org.apache.servicecomb.pack.alpha.fsm.SagaActorState; +import org.apache.servicecomb.pack.alpha.fsm.TransactionType; +import org.apache.servicecomb.pack.alpha.fsm.TxState; +import org.apache.servicecomb.pack.alpha.fsm.event.SagaEndedEvent; +import org.apache.servicecomb.pack.alpha.fsm.event.SagaStartedEvent; +import org.apache.servicecomb.pack.alpha.fsm.event.TxEndedEvent; +import org.apache.servicecomb.pack.alpha.fsm.event.TxStartedEvent; +import org.apache.servicecomb.pack.alpha.fsm.event.base.BaseEvent; +import org.apache.servicecomb.pack.alpha.fsm.metrics.MetricsBean; +import org.apache.servicecomb.pack.alpha.fsm.metrics.MetricsService; +import org.apache.servicecomb.pack.alpha.fsm.repository.TransactionRepository; +import org.apache.servicecomb.pack.alpha.fsm.repository.model.GlobalTransaction; +import org.apache.servicecomb.pack.alpha.fsm.repository.model.PagingGloablTransactions; +import org.apache.servicecomb.pack.alpha.fsm.repository.model.SagaSubTransaction; +import org.apache.servicecomb.pack.alpha.server.metrics.AlphaMetrics; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + +@RunWith(SpringRunner.class) +@WebMvcTest(value = {APIControllerV1.class, AlphaMetrics.class}) +public class APIControllerV1Tests { + + @Autowired + private MockMvc mockMvc; + + @Autowired + AlphaMetrics alphaMetrics; + + @MockBean + MetricsService metricsService; + + @MockBean + NodeStatus nodeStatus; + + @MockBean + ElasticsearchTemplate template; + + @MockBean + TransactionRepository transactionRepository; + + @Test + public void metricsTest() throws Exception { + MetricsBean metricsBean = new MetricsBean(); + metricsBean.doEventReceived(); + metricsBean.doEventAccepted(); + metricsBean.doEventAvgTime(5); + metricsBean.doActorReceived(); + metricsBean.doActorAccepted(); + metricsBean.doActorAvgTime(5); + metricsBean.doRepositoryReceived(); + metricsBean.doRepositoryAccepted(); + metricsBean.doRepositoryAvgTime(5); + metricsBean.doCommitted(); + metricsBean.doCompensated(); + metricsBean.doSuspended(); + metricsBean.doSagaBeginCounter(); + metricsBean.doSagaEndCounter(); + metricsBean.doSagaAvgTime(5); + when(metricsService.metrics()).thenReturn(metricsBean); + when(nodeStatus.getTypeEnum()).thenReturn(TypeEnum.MASTER); + mockMvc.perform(get("/alpha/api/v1/metrics")) + .andExpect(status().isOk()) + .andExpect( + MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.metrics.eventReceived").value(1)) + .andExpect(jsonPath("$.metrics.eventAccepted").value(1)) + .andExpect(jsonPath("$.metrics.eventRejected").value(0)) + .andExpect(jsonPath("$.metrics.eventAvgTime").value(5.0)) + .andExpect(jsonPath("$.metrics.actorReceived").value(1)) + .andExpect(jsonPath("$.metrics.actorAccepted").value(1)) + .andExpect(jsonPath("$.metrics.actorRejected").value(0)) + .andExpect(jsonPath("$.metrics.actorAvgTime").value(5.0)) + .andExpect(jsonPath("$.metrics.repositoryReceived").value(1)) + .andExpect(jsonPath("$.metrics.repositoryAccepted").value(1)) + .andExpect(jsonPath("$.metrics.repositoryRejected").value(0)) + .andExpect(jsonPath("$.metrics.repositoryAvgTime").value(5.0)) + .andExpect(jsonPath("$.metrics.sagaBeginCounter").value(1)) + .andExpect(jsonPath("$.metrics.sagaEndCounter").value(1)) + .andExpect(jsonPath("$.metrics.sagaAvgTime").value(5.0)) + .andExpect(jsonPath("$.metrics.committed").value(1)) + .andExpect(jsonPath("$.metrics.compensated").value(1)) + .andExpect(jsonPath("$.metrics.suspended").value(1)) + .andExpect(jsonPath("$.nodeType").value(TypeEnum.MASTER.name())) + .andReturn(); + } + + @Test + public void transactionTest() throws Exception { + final String serviceName = "serviceName-1"; + final String instanceId = "instanceId-1"; + final String globalTxId = UUID.randomUUID().toString(); + final String localTxId_1 = UUID.randomUUID().toString(); + final String localTxId_2 = UUID.randomUUID().toString(); + final String localTxId_3 = UUID.randomUUID().toString(); + + List<BaseEvent> events = new ArrayList(); + events.add(SagaStartedEvent.builder().serviceName("service_g").instanceId("instance_g") + .globalTxId(globalTxId).build()); + events.add(TxStartedEvent.builder().serviceName("service_c1").instanceId("instance_c1") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_1).build()); + events.add(TxEndedEvent.builder().serviceName("service_c1").instanceId("instance_c1") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_1).build()); + events.add(TxStartedEvent.builder().serviceName("service_c2").instanceId("instance_c2") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_2).build()); + events.add(TxEndedEvent.builder().serviceName("service_c2").instanceId("instance_c2") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_2).build()); + events.add(TxStartedEvent.builder().serviceName("service_c3").instanceId("instance_c3") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_3).build()); + events.add(TxEndedEvent.builder().serviceName("service_c3").instanceId("instance_c3") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_3).build()); + events.add(SagaEndedEvent.builder().serviceName("service_g").instanceId("instance_g") + .globalTxId(globalTxId).build()); + + List<SagaSubTransaction> subTransactions = new ArrayList(); + subTransactions + .add(SagaSubTransaction.builder().parentTxId(globalTxId).localTxId(localTxId_1).state( + TxState.COMMITTED).beginTime(new Date()).endTime(new Date()).build()); + subTransactions + .add(SagaSubTransaction.builder().parentTxId(globalTxId).localTxId(localTxId_2).state( + TxState.COMMITTED).beginTime(new Date()).endTime(new Date()).build()); + subTransactions + .add(SagaSubTransaction.builder().parentTxId(globalTxId).localTxId(localTxId_3).state( + TxState.COMMITTED).beginTime(new Date()).endTime(new Date()).build()); + + List<GlobalTransaction> globalTransactions = new ArrayList<>(); + globalTransactions.add(GlobalTransaction.builder() + .serviceName(serviceName) + .instanceId(instanceId) + .globalTxId(globalTxId) + .type(TransactionType.SAGA) + .state(SagaActorState.COMMITTED) + .beginTime(new Date()) + .endTime(new Date()) + .subTxSize(3) + .events(events) + .subTransactions(subTransactions) + .build()); + PagingGloablTransactions paging = PagingGloablTransactions.builder() + .page(0) + .size(50) + .elapsed(10) + .total(1) + .gloablTransactions(globalTransactions) + .build(); + + when(transactionRepository.getGloablTransactions(0, 50)).thenReturn(paging); + + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false); + mapper.configure(Feature.QUOTE_NON_NUMERIC_NUMBERS, false); + mockMvc.perform(get("/alpha/api/v1/transaction?page=0&size=50")) + .andExpect(status().isOk()) + .andExpect( + MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.total").value(1)) + .andExpect(jsonPath("$.page").value(0)) + .andExpect(jsonPath("$.size").value(50)) + .andExpect(jsonPath("$.elapsed").value(10)) + .andExpect(jsonPath("$.globalTransactions", hasSize(1))) + .andExpect(jsonPath("$.globalTransactions[0].globalTxId") + .value(globalTransactions.get(0).getGlobalTxId())) + .andExpect(jsonPath("$.globalTransactions[0].type") + .value(globalTransactions.get(0).getType().name())) + .andExpect(jsonPath("$.globalTransactions[0].serviceName") + .value(globalTransactions.get(0).getServiceName())) + .andExpect(jsonPath("$.globalTransactions[0].instanceId") + .value(globalTransactions.get(0).getInstanceId())) + .andExpect(jsonPath("$.globalTransactions[0].beginTime") + .value(globalTransactions.get(0).getBeginTime().getTime())) + .andExpect(jsonPath("$.globalTransactions[0].endTime") + .value(globalTransactions.get(0).getEndTime().getTime())) + .andExpect(jsonPath("$.globalTransactions[0].state") + .value(globalTransactions.get(0).getState().name())) + .andExpect(jsonPath("$.globalTransactions[0].subTxSize") + .value(globalTransactions.get(0).getSubTxSize())) + .andExpect(jsonPath("$.globalTransactions[0].durationTime") + .value(globalTransactions.get(0).getDurationTime())) + .andExpect(jsonPath("$.globalTransactions[0].subTransactions", hasSize(3))) + .andExpect(jsonPath("$.globalTransactions[0].events", hasSize(8))) + .andReturn(); + } + + @Test + public void globalTransactionByGlobalTxIdTest() throws Exception { + final String serviceName = "serviceName-1"; + final String instanceId = "instanceId-1"; + final String globalTxId = UUID.randomUUID().toString(); + final String localTxId_1 = UUID.randomUUID().toString(); + final String localTxId_2 = UUID.randomUUID().toString(); + final String localTxId_3 = UUID.randomUUID().toString(); + + List<BaseEvent> events = new ArrayList(); + events.add(SagaStartedEvent.builder().serviceName("service_g").instanceId("instance_g") + .globalTxId(globalTxId).build()); + events.add(TxStartedEvent.builder().serviceName("service_c1").instanceId("instance_c1") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_1).build()); + events.add(TxEndedEvent.builder().serviceName("service_c1").instanceId("instance_c1") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_1).build()); + events.add(TxStartedEvent.builder().serviceName("service_c2").instanceId("instance_c2") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_2).build()); + events.add(TxEndedEvent.builder().serviceName("service_c2").instanceId("instance_c2") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_2).build()); + events.add(TxStartedEvent.builder().serviceName("service_c3").instanceId("instance_c3") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_3).build()); + events.add(TxEndedEvent.builder().serviceName("service_c3").instanceId("instance_c3") + .globalTxId(globalTxId).parentTxId(globalTxId).localTxId(localTxId_3).build()); + events.add(SagaEndedEvent.builder().serviceName("service_g").instanceId("instance_g") + .globalTxId(globalTxId).build()); + + List<SagaSubTransaction> subTransactions = new ArrayList(); + subTransactions + .add(SagaSubTransaction.builder().parentTxId(globalTxId).localTxId(localTxId_1).state( + TxState.COMMITTED).beginTime(new Date()).endTime(new Date()).build()); + subTransactions + .add(SagaSubTransaction.builder().parentTxId(globalTxId).localTxId(localTxId_2).state( + TxState.COMMITTED).beginTime(new Date()).endTime(new Date()).build()); + subTransactions + .add(SagaSubTransaction.builder().parentTxId(globalTxId).localTxId(localTxId_3).state( + TxState.COMMITTED).beginTime(new Date()).endTime(new Date()).build()); + + GlobalTransaction globalTransaction = GlobalTransaction.builder() + .serviceName(serviceName) + .instanceId(instanceId) + .globalTxId(globalTxId) + .type(TransactionType.SAGA) + .state(SagaActorState.COMMITTED) + .beginTime(new Date()) + .endTime(new Date()) + .subTxSize(3) + .events(events) + .subTransactions(subTransactions) + .build(); + + when(transactionRepository.getGloablTransactionByGlobalTxId(globalTxId)).thenReturn(globalTransaction); + + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false); + mapper.configure(Feature.QUOTE_NON_NUMERIC_NUMBERS, false); + mockMvc.perform(get("/alpha/api/v1/transaction/"+globalTxId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect( + MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.globalTxId") + .value(globalTransaction.getGlobalTxId())) + .andExpect(jsonPath("$.type") + .value(globalTransaction.getType().name())) + .andExpect(jsonPath("$.serviceName") + .value(globalTransaction.getServiceName())) + .andExpect(jsonPath("$.instanceId") + .value(globalTransaction.getInstanceId())) + .andExpect(jsonPath("$.beginTime") + .value(globalTransaction.getBeginTime().getTime())) + .andExpect(jsonPath("$.endTime") + .value(globalTransaction.getEndTime().getTime())) + .andExpect(jsonPath("$.state") + .value(globalTransaction.getState().name())) + .andExpect(jsonPath("$.subTxSize") + .value(globalTransaction.getSubTxSize())) + .andExpect(jsonPath("$.durationTime") + .value(globalTransaction.getDurationTime())) + .andExpect(jsonPath("$.subTransactions", hasSize(3))) + .andExpect(jsonPath("$.events", hasSize(8))) + .andReturn(); + } +}
