From e71d6b73ddaaa82bce7da8c50fb9f57c75617cfb Mon Sep 17 00:00:00 2001 From: zhou-yinyuan <147299494+zhou-yinyuan@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:49:22 +0800 Subject: [PATCH] ADM-965 [frontend][backend]: add a heartbeat state 'Design' &'Waiting for deployment' in board mapping (#1568) * ADM-965 [frontend]: rename the waiting for testing * ADM-990 [frontend]: add design and waiting for development to cycle time options * ADM-990 [backend]: add design and waiting for development to cycle time result and rework * ADM-990 [backend]: fix sonar issues * ADM-965 [frontend]: change the cycle time data in the report page * ADM-965 [frontend]: show the rework data in the board detail page * ADM-965 [frontend]: fix test * ADM-965 [frontend]: fix e2e test * ADM-965 [frontend]: rename * ADM-965 [backend]: fix comments * ADM-965 [backend]: fix sonar issues --- README.md | 24 +- .../board/dto/request/CardStepsEnum.java | 24 +- .../board/dto/response/StepsDay.java | 4 + .../report/dto/response/Rework.java | 4 + .../service/board/jira/JiraService.java | 11 +- .../report/calculator/ReworkCalculator.java | 5 +- .../jira/JiraBoardConfigDTOFixture.java | 11 + .../service/jira/JiraServiceTest.java | 3601 ++++++++--------- .../service/report/BoardCsvFixture.java | 2 +- .../service/report/ReworkFixture.java | 13 +- .../containers/MetricsStep/CycleTime.test.tsx | 12 +- frontend/__tests__/fixtures.ts | 6 + .../hooks/reportMapper/report.test.tsx | 28 +- frontend/__tests__/utils/Util.test.tsx | 4 +- .../e2e/fixtures/create-new/metrics-step.ts | 31 + .../e2e/fixtures/create-new/report-result.ts | 193 +- frontend/e2e/pages/metrics/report-step.ts | 18 +- .../major-path/create-a-new-project.spec.ts | 77 +- .../import-project-from-file.spec.ts | 4 +- frontend/src/clients/report/ReportClient.ts | 2 + frontend/src/clients/report/dto/response.ts | 2 + frontend/src/constants/resources.ts | 26 +- frontend/src/hooks/reportMapper/cycleTime.ts | 48 +- 23 files changed, 2250 insertions(+), 1900 deletions(-) diff --git a/README.md b/README.md index fb7d5662cb..eff01f9683 100644 --- a/README.md +++ b/README.md @@ -242,17 +242,19 @@ _Image 3-9, Crews/Board Mappings config_ **Cycle Time:** It will list all columns for the current active jira board. Then users need to map the each column to the supported columns. Like, if your board have “in progress” column, it means developer doing this ticket, so it should be mapping with “In Dev” for the list we provide. -| Status | Description | -| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| To do | It means the ticket needs to be done, waiting for Dev to pick it. Cycle time doesn't include this time. | -| Analysis | BA or other people still need to analyze the ticket. Cycle time doesn't include this time. | -| In Dev | It means dev is doing the ticket. This time should be a part of cycle time. And it is named development time. | -| Block | It means the tickets blocked by some issues, cannot be done now. This time should be a part of cycle time. And it is named block time. | -| Waiting for testing | It means waiting for Dev to pick or QA to testing. This time should be a part of cycle time. And it is named waiting time. | -| Testing | It means QA is testing the tickets. This time should be a part of cycle time. And it is named testing time. | -| Review | It means PO or other people are reviewing the tickets. This time should be a part of cycle time. And it is named review time. | -| Done | It means the tickets are already done. Cycle time doesn't include this time. | -| -- | If you don't need to map, you can select -- | +| Status | Description | +|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| To do | It means the ticket needs to be done, waiting for Dev to pick it. Cycle time doesn't include this time. | +| Analysis | BA or other people still need to analyze the ticket. Cycle time doesn't include this time. | +| Design | UX or other people still need to design the prototype.Cycle time doesn’t include this time. | +| In Dev | It means dev is doing the ticket. This time should be a part of cycle time. And it is named development time. | +| Block | It means the tickets blocked by some issues, cannot be done now. This time should be a part of cycle time. And it is named block time. | +| Waiting for testing | It means waiting for Dev to pick or QA to testing. This time should be a part of cycle time. And it is named waiting time. | +| Testing | It means QA is testing the tickets. This time should be a part of cycle time. And it is named testing time. | +| Review | It means PO or other people are reviewing the tickets. This time should be a part of cycle time. And it is named review time. | +| Waiting for deployment | it means that the ticket has passed the test and is waiting to be deployment. This time should be a part of cycle time. And it is named waiting for deployment time. | +| Done | It means the tickets are already done. Cycle time doesn't include this time. | +| -- | If you don't need to map, you can select -- | **By Status**: user can click the toggle selected button to choose the mapping relationship by column or by status. It support multiple status map in to one column, just as the picture shows the TODO and INPROGRESS board status can be mapped to different heartbeat states. diff --git a/backend/src/main/java/heartbeat/controller/board/dto/request/CardStepsEnum.java b/backend/src/main/java/heartbeat/controller/board/dto/request/CardStepsEnum.java index 7ee6bc3394..0094486b14 100644 --- a/backend/src/main/java/heartbeat/controller/board/dto/request/CardStepsEnum.java +++ b/backend/src/main/java/heartbeat/controller/board/dto/request/CardStepsEnum.java @@ -5,9 +5,11 @@ public enum CardStepsEnum { - TODO("To do", "To do"), ANALYSE("Analysis", "Analysis"), DEVELOPMENT("In Dev", "In dev"), BLOCK("Block", "Block"), - FLAG("FLAG", "Flag"), REMOVEFLAG("removeFlag", "Remove flag"), REVIEW("Review", "Review"), - WAITING("Waiting for testing", "Waiting for testing"), TESTING("Testing", "Testing"), DONE("Done", "Done"), + TODO("To do", "To do"), ANALYSE("Analysis", "Analysis"), DESIGN("Design", "Design"), + DEVELOPMENT("In Dev", "In dev"), BLOCK("Block", "Block"), FLAG("FLAG", "Flag"), + REMOVEFLAG("removeFlag", "Remove flag"), REVIEW("Review", "Review"), + WAITING_FOR_TESTING("Waiting for testing", "Waiting for testing"), TESTING("Testing", "Testing"), + WAITING_FOR_DEPLOYMENT("Waiting for deployment", "Waiting for deployment"), DONE("Done", "Done"), CLOSED("Closed", "Closed"), UNKNOWN("UNKNOWN", "Unknown"); private final String value; @@ -37,9 +39,17 @@ public static CardStepsEnum fromValue(String type) { } public static final Map> reworkJudgmentMap = Map.of(TODO, - Set.of(ANALYSE, DEVELOPMENT, BLOCK, FLAG, REVIEW, WAITING, TESTING, DONE), ANALYSE, - Set.of(DEVELOPMENT, BLOCK, FLAG, REVIEW, WAITING, TESTING, DONE), DEVELOPMENT, - Set.of(BLOCK, FLAG, REVIEW, WAITING, TESTING, DONE), BLOCK, Set.of(REVIEW, WAITING, TESTING, DONE), REVIEW, - Set.of(WAITING, TESTING, DONE), WAITING, Set.of(TESTING, DONE), TESTING, Set.of(DONE)); + Set.of(ANALYSE, DESIGN, DEVELOPMENT, BLOCK, FLAG, REVIEW, WAITING_FOR_TESTING, TESTING, + WAITING_FOR_DEPLOYMENT, DONE), + ANALYSE, + Set.of(DESIGN, DEVELOPMENT, BLOCK, FLAG, REVIEW, WAITING_FOR_TESTING, TESTING, WAITING_FOR_DEPLOYMENT, + DONE), + DESIGN, + Set.of(DEVELOPMENT, BLOCK, FLAG, REVIEW, WAITING_FOR_TESTING, TESTING, WAITING_FOR_DEPLOYMENT, DONE), + DEVELOPMENT, Set.of(BLOCK, FLAG, REVIEW, WAITING_FOR_TESTING, TESTING, WAITING_FOR_DEPLOYMENT, DONE), BLOCK, + Set.of(REVIEW, WAITING_FOR_TESTING, TESTING, WAITING_FOR_DEPLOYMENT, DONE), REVIEW, + Set.of(WAITING_FOR_TESTING, TESTING, WAITING_FOR_DEPLOYMENT, DONE), WAITING_FOR_TESTING, + Set.of(TESTING, WAITING_FOR_DEPLOYMENT, DONE), TESTING, Set.of(WAITING_FOR_DEPLOYMENT, DONE), + WAITING_FOR_DEPLOYMENT, Set.of(DONE)); } diff --git a/backend/src/main/java/heartbeat/controller/board/dto/response/StepsDay.java b/backend/src/main/java/heartbeat/controller/board/dto/response/StepsDay.java index 08ad1bf6a4..85f6cadb1b 100644 --- a/backend/src/main/java/heartbeat/controller/board/dto/response/StepsDay.java +++ b/backend/src/main/java/heartbeat/controller/board/dto/response/StepsDay.java @@ -25,4 +25,8 @@ public class StepsDay { private double todo; + private double design; + + private double waitingForDeployment; + } diff --git a/backend/src/main/java/heartbeat/controller/report/dto/response/Rework.java b/backend/src/main/java/heartbeat/controller/report/dto/response/Rework.java index c3f462d278..1a9a3a492a 100644 --- a/backend/src/main/java/heartbeat/controller/report/dto/response/Rework.java +++ b/backend/src/main/java/heartbeat/controller/report/dto/response/Rework.java @@ -15,6 +15,8 @@ public class Rework { private Integer fromAnalysis; + private Integer fromDesign; + private Integer fromInDev; private Integer fromBlock; @@ -23,6 +25,8 @@ public class Rework { private Integer fromTesting; + private Integer fromWaitingForDeployment; + private Integer fromReview; private Integer fromDone; diff --git a/backend/src/main/java/heartbeat/service/board/jira/JiraService.java b/backend/src/main/java/heartbeat/service/board/jira/JiraService.java index a8ebd03a56..13dc3b7079 100644 --- a/backend/src/main/java/heartbeat/service/board/jira/JiraService.java +++ b/backend/src/main/java/heartbeat/service/board/jira/JiraService.java @@ -910,7 +910,6 @@ private List putStatusChangeEventsIntoAnArray(CardHistoryResp }); } return statusChangedArray; - } private CardCycleTime calculateCardCycleTime(String cardId, List cycleTimeInfos, @@ -932,7 +931,7 @@ private CardCycleTime calculateCardCycleTime(String cardId, List stepsDay.setDevelopment(stepsDay.getDevelopment() + cycleTimeInfo.getDay()); total += cycleTimeInfo.getDay(); } - case WAITING -> { + case WAITING_FOR_TESTING -> { stepsDay.setWaitingForTesting(stepsDay.getWaitingForTesting() + cycleTimeInfo.getDay()); total += cycleTimeInfo.getDay(); } @@ -940,6 +939,10 @@ private CardCycleTime calculateCardCycleTime(String cardId, List stepsDay.setTesting(stepsDay.getTesting() + cycleTimeInfo.getDay()); total += cycleTimeInfo.getDay(); } + case WAITING_FOR_DEPLOYMENT -> { + stepsDay.setWaitingForDeployment(stepsDay.getWaitingForDeployment() + cycleTimeInfo.getDay()); + total += cycleTimeInfo.getDay(); + } case BLOCK -> { stepsDay.setBlocked(stepsDay.getBlocked() + cycleTimeInfo.getDay()); total += cycleTimeInfo.getDay(); @@ -948,6 +951,10 @@ private CardCycleTime calculateCardCycleTime(String cardId, List stepsDay.setReview(stepsDay.getReview() + cycleTimeInfo.getDay()); total += cycleTimeInfo.getDay(); } + case DESIGN -> { + stepsDay.setDesign(stepsDay.getDesign() + cycleTimeInfo.getDay()); + total += cycleTimeInfo.getDay(); + } case ANALYSE -> { stepsDay.setAnalyse(stepsDay.getAnalyse() + cycleTimeInfo.getDay()); total += cycleTimeInfo.getDay(); diff --git a/backend/src/main/java/heartbeat/service/report/calculator/ReworkCalculator.java b/backend/src/main/java/heartbeat/service/report/calculator/ReworkCalculator.java index b921b6e532..83d4b165f4 100644 --- a/backend/src/main/java/heartbeat/service/report/calculator/ReworkCalculator.java +++ b/backend/src/main/java/heartbeat/service/report/calculator/ReworkCalculator.java @@ -28,14 +28,17 @@ public Rework calculateRework(CardCollection realDoneCardCollection, CardStepsEn switch (reworkTimesInfo.getState()) { case ANALYSE -> rework.setFromAnalysis(Optional.ofNullable(rework.getFromAnalysis()).orElse(0) + times); + case DESIGN -> rework.setFromDesign(Optional.ofNullable(rework.getFromDesign()).orElse(0) + times); case DEVELOPMENT -> rework.setFromInDev(Optional.ofNullable(rework.getFromInDev()).orElse(0) + times); case BLOCK -> rework.setFromBlock(Optional.ofNullable(rework.getFromBlock()).orElse(0) + times); - case WAITING -> rework.setFromWaitingForTesting( + case WAITING_FOR_TESTING -> rework.setFromWaitingForTesting( Optional.ofNullable(rework.getFromWaitingForTesting()).orElse(0) + times); case TESTING -> rework.setFromTesting(Optional.ofNullable(rework.getFromTesting()).orElse(0) + times); case REVIEW -> rework.setFromReview(Optional.ofNullable(rework.getFromReview()).orElse(0) + times); + case WAITING_FOR_DEPLOYMENT -> rework.setFromWaitingForDeployment( + Optional.ofNullable(rework.getFromWaitingForDeployment()).orElse(0) + times); case DONE -> rework.setFromDone(Optional.ofNullable(rework.getFromDone()).orElse(0) + times); default -> throw new IllegalStateException("Unexpected value: " + reworkTimesInfo.getState()); } diff --git a/backend/src/test/java/heartbeat/service/jira/JiraBoardConfigDTOFixture.java b/backend/src/test/java/heartbeat/service/jira/JiraBoardConfigDTOFixture.java index 946d776b6f..9aa753d218 100644 --- a/backend/src/test/java/heartbeat/service/jira/JiraBoardConfigDTOFixture.java +++ b/backend/src/test/java/heartbeat/service/jira/JiraBoardConfigDTOFixture.java @@ -50,6 +50,8 @@ public class JiraBoardConfigDTOFixture { public static final String ANALYSE = "Analysis"; + public static final String DESIGN = "Design"; + public static final String IN_DEV = "In Dev"; public static final String REVIEW = "Review"; @@ -66,6 +68,8 @@ public class JiraBoardConfigDTOFixture { public static final String WAITING_FOR_TESTING = "Waiting for testing"; + public static final String WAITING_FOR_DEPLOYMENT = "Waiting for deployment"; + public static final String ASSIGNEE_NAME = "Zhang San"; public static final String DISPLAY_NAME_ONE = "Da Pei"; @@ -448,6 +452,11 @@ public static JiraBoardSetting.JiraBoardSettingBuilder JIRA_BOARD_SETTING_BUILD( .boardId(BOARD_ID) .boardColumns(List.of(RequestJiraBoardColumnSetting.builder().name(IN_DEV).value(IN_DEV).build(), RequestJiraBoardColumnSetting.builder().name(ANALYSE).value(ANALYSE).build(), + RequestJiraBoardColumnSetting.builder().name(DESIGN).value(DESIGN).build(), + RequestJiraBoardColumnSetting.builder() + .name(WAITING_FOR_DEPLOYMENT) + .value(WAITING_FOR_DEPLOYMENT) + .build(), RequestJiraBoardColumnSetting.builder() .name(WAITING_FOR_TESTING) .value(WAITING_FOR_TESTING) @@ -650,6 +659,8 @@ public static List CYCLE_TIME_INFO_LIST() { CycleTimeInfo.builder().column("IN DEV").day(3.0).build(), CycleTimeInfo.builder().column("REVIEW").day(4.0).build(), CycleTimeInfo.builder().column("ANALYSIS").day(9.0).build(), + CycleTimeInfo.builder().column("DESIGN").day(1.0).build(), + CycleTimeInfo.builder().column("WAITING FOR DEPLOYMENT").day(2.0).build(), CycleTimeInfo.builder().column(UNKNOWN).day(5.0).build(), CycleTimeInfo.builder().column("BLOCK").day(6.0).build()); } diff --git a/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java b/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java index 7e8067fdda..4c249422ff 100644 --- a/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java +++ b/backend/src/test/java/heartbeat/service/jira/JiraServiceTest.java @@ -46,6 +46,7 @@ import heartbeat.util.SystemUtil; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -164,6 +165,10 @@ class JiraServiceTest { ObjectMapper objectMapper = new ObjectMapper(); + String token = "token"; + + ZoneId zoneId = ZoneId.of("Asia/Shanghai"); + @BeforeEach public void setUp() { jiraService = new JiraService(executor = getTaskExecutor(), jiraFeignClient, urlGenerator, boardUtil, @@ -186,1839 +191,1777 @@ public ThreadPoolTaskExecutor getTaskExecutor() { return executor; } - @Test - @Deprecated - void shouldCallJiraFeignClientAndReturnBoardConfigResponseWhenGetJiraBoardConfig() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of( - new TargetField("customfield_10016", "Story point estimate", false), - new TargetField("customfield_10020", "Sprint", false), - new TargetField("customfield_10021", "Flagged", false)); - - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam); - jiraService.shutdownExecutor(); - - assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)).isEqualTo("DOING"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - void shouldCallJiraFeignClientAndReturnBoardInfoResponseWhenGetJiraBoardInfo() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of( - new TargetField("customfield_10016", "Story point estimate", false), - new TargetField("customfield_10020", "Sprint", false), - new TargetField("customfield_10021", "Flagged", false)); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); - jiraService.shutdownExecutor(); - assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)).isEqualTo("DOING"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - void shouldCallJiraFeignClientAndReturnBoardVerifyResponseWhenVerifyJiraBoard() { - JiraBoardVerifyDTO jiraBoardVerifyDTO = JIRA_BOARD_VERIFY_RESPONSE_BUILDER().build(); - BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - - doReturn(jiraBoardVerifyDTO).when(jiraFeignClient) - .getBoard(baseUrl, boardVerifyRequestParam.getBoardId(), boardVerifyRequestParam.getToken()); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - - String projectKey = jiraService.verify(BoardType.JIRA, boardVerifyRequestParam); - jiraService.shutdownExecutor(); - assertThat(Objects.requireNonNull(projectKey)).isEqualTo("ADM"); - } - - @Test - @Deprecated - void shouldCallJiraFeignClientAndReturnBoardConfigResponseWhenGetJiraBoardConfigHasTwoPage() throws IOException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of( - new TargetField("customfield_10016", "Story point estimate", false), - new TargetField("customfield_10020", "Sprint", false), - new TargetField("customfield_10021", "Flagged", false)); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_TWO_PAGES_CARDS_RESPONSE_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 100, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam); - assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)).isEqualTo("DOING"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getTargetFields()).hasSize(3); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - void shouldCallJiraFeignClientAndReturnBoardInfoResponseWhenGetJiraBoardInfoHasTwoPage() throws IOException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of( - new TargetField("customfield_10016", "Story point estimate", false), - new TargetField("customfield_10020", "Sprint", false), - new TargetField("customfield_10021", "Flagged", false)); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_TWO_PAGES_CARDS_RESPONSE_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 100, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); - assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)).isEqualTo("DOING"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getTargetFields()).hasSize(3); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - @Deprecated - void shouldCallJiraFeignClientAndReturnBoardConfigResponseWhenGetClassicJiraBoardConfig() - throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of( - new TargetField("customfield_10016", "Story point estimate", false), - new TargetField("customfield_10020", "Sprint", false), - new TargetField("customfield_10021", "Flagged", false)); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)).thenReturn(completeStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeClassicJira, boardRequestParam); - - assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)).isEqualTo("DOING"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getTargetFields()).hasSize(3); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - void shouldCallJiraFeignClientAndReturnBoardInfoResponseWhenGetClassicJiraBoardInfo() - throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of( - new TargetField("customfield_10016", "Story point estimate", false), - new TargetField("customfield_10020", "Sprint", false), - new TargetField("customfield_10021", "Flagged", false)); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("classic").build()); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)).thenReturn(completeStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); - assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)).isEqualTo("DOING"); - assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getTargetFields()).hasSize(3); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - @Deprecated - void shouldCallJiraFeignClientAndThrowParamExceptionWhenGetJiraBoardConfig() { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - assertThatThrownBy(() -> jiraService.getJiraConfiguration(null, boardRequestParam)) - .isInstanceOf(BadRequestException.class) - .hasMessageContaining("boardType param is not correct"); - } - - @Test - void shouldCallJiraFeignClientAndThrowParamExceptionWhenGetJiraBoardInfo() { - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - assertThatThrownBy(() -> jiraService.getInfo(null, boardRequestParam)).isInstanceOf(BadRequestException.class) - .hasMessageContaining("boardType param is not correct"); - } - - @Test - void shouldThrowExceptionWhenVerifyJiraBoardTypeNotCorrect() { - BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); - - assertThatThrownBy(() -> jiraService.verify(BoardType.CLASSIC_JIRA, boardVerifyRequestParam)) - .isInstanceOf(BadRequestException.class) - .hasMessageContaining("boardType param is not correct"); - } - - @Test - void shouldCallJiraFeignClientAndThrowNonColumnWhenVerifyJiraBoard() { - JiraBoardVerifyDTO jiraBoardVerifyDTO = JIRA_BOARD_VERIFY_FAILED_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doReturn(jiraBoardVerifyDTO).when(jiraFeignClient).getBoard(baseUrl, BOARD_ID, token); - - Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); - assertThat(thrown).isInstanceOf(InternalServerErrorException.class) - .hasMessageContaining("Failed to call Jira to verify board, cause is"); - } - - @Test - void shouldCallJiraFeignClientAndThrowBaseExceptionWhenVerifyJiraBoard() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doThrow(new UnauthorizedException("")).when(jiraFeignClient) - .getBoard(baseUrl, boardVerifyRequestParam.getBoardId(), boardVerifyRequestParam.getToken()); - - Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); - assertThat(thrown).isInstanceOf(BaseException.class); - } - - @Test - void shouldCallJiraFeignClientBoardAndThrowNotFoundWhenVerifyJiraBoard() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doThrow(new NotFoundException("boardId is incorrect")).when(jiraFeignClient).getBoard(baseUrl, BOARD_ID, token); - - Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); - assertThat(thrown).isInstanceOf(RuntimeException.class).hasMessageContaining("boardId is incorrect"); - } - - @Test - void shouldCallJiraFeignClientBoardAndThrowNotFoundWhenVerifyJiraBoardSite() { - URI baseUrl = URI.create(INVALID_SITE_ATLASSIAN_NET); - String token = "token"; - BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(INVALID_SITE_ATLASSIAN_NET)); - doThrow(new NotFoundException("site is incorrect")).when(jiraFeignClient).getDashboard(baseUrl, token); - - Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); - assertThat(thrown).isInstanceOf(RuntimeException.class).hasMessageContaining("site is incorrect"); - - } - - @Test - @Deprecated - void shouldCallJiraFeignClientAndThrowNotFoundExceptionWhenGetJiraBoardConfig() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)) - .thenThrow(new NotFoundException("message")); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(new CardHistoryResponseDTO(true, Collections.emptyList())); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - assertThatCode(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) - .doesNotThrowAnyException(); - } - - @Test - void shouldCallJiraFeignClientTwiceGivenTwoPageHistoryDataWhenGetJiraBoardConfig() throws JsonProcessingException { - // given - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - - JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() - .build(); - String allDoneCards = objectMapper.writeValueAsString(NEED_FILTERED_ALL_DONE_CARDS_BUILDER().build()); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(new CardHistoryResponseDTO(false, new ArrayList<>( - List.of(new HistoryDetail(1, "status", new Status("To do"), new Status("Block"), null, null))))); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 100, 100, token)) - .thenReturn(new CardHistoryResponseDTO(true, new ArrayList<>( - List.of(new HistoryDetail(2, "assignee", new Status("In Dev"), new Status("To do"), null, null))))); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - // when - jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(storyPointsAndCycleTimeRequest, - jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - // then - verify(jiraFeignClient, times(2)).getJiraCardHistoryByCount(any(), eq("2"), anyInt(), anyInt(), any()); - } - - @Test - @Deprecated - void shouldCallJiraFeignClientAndThrowNonContentCodeWhenGetJiraBoardConfig() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)) - .thenReturn(objectMapper.writeValueAsString(ONE_PAGE_NO_DONE_CARDS_RESPONSE_BUILDER().build())); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) - .isInstanceOf(NoContentException.class) - .hasMessageContaining("There is no cards."); - } - - @Test - void shouldCallJiraFeignClientAndThrowNonContentCodeWhenGetJiraBoardInfo() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)) - .thenReturn(objectMapper.writeValueAsString(ONE_PAGE_NO_DONE_CARDS_RESPONSE_BUILDER().build())); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)) - .isInstanceOf(NoContentException.class) - .hasMessageContaining("There is no cards."); - } - - @Test - @Deprecated - void shouldCallJiraFeignClientAndThrowNonColumnWhenGetJiraBoardConfig() { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO noneStatusSelf = NONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(noneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - Throwable thrown = catchThrowable(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)); - assertThat(thrown).isInstanceOf(InternalServerErrorException.class) - .hasMessageContaining("Failed to call Jira to get board config, cause is"); - } - - @Test - void shouldCallJiraFeignClientAndThrowNonColumnWhenGetJiraBoardInfo() { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO noneStatusSelf = NONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(noneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - Throwable thrown = catchThrowable(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)); - assertThat(thrown).isInstanceOf(InternalServerErrorException.class) - .hasMessageContaining("Failed to call Jira to get board info, cause is"); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeGivenStoryPointKeyFromEnvironmentVariable() - throws JsonProcessingException { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", - boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - Map envMap = new HashMap<>(); - envMap.put("STORY_POINT_KEY", "customfield_10016"); - - AllCardsResponseDTO allCardsResponseDTO = ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build(); - String allDoneCards = objectMapper.writeValueAsString(allCardsResponseDTO) - .replaceAll("\"storyPoints\":5.0", "\"customfield_10016\":null") - .replaceAll("storyPoints", "customfield_10016"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(systemUtil.getEnvMap()).thenReturn(envMap); - - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - jiraBoardSetting - .setOverrideFields(List.of(TargetField.builder().key("").name("Story Points").flag(true).build(), - TargetField.builder().key("").name("Flagged").flag(true).build())); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getStoryPointSum()).isEqualTo(6.0); - assertThat(cardCollection.getCardsNumber()).isEqualTo(4); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeGivenStoryPointKeyFromEnvironmentVariableWhenTargetFieldIsTrue() - throws JsonProcessingException { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", - boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - Map envMap = new HashMap<>(); - envMap.put("STORY_POINT_KEY", "storyPoints"); - - AllCardsResponseDTO allCardsResponseDTO = ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build(); - allCardsResponseDTO.getIssues() - .add(JiraCard.builder() - .key("2") - .fields(JiraCardField.builder().assignee(new Assignee("Test 1")).storyPoints(0).build()) - .build()); - String allDoneCards = objectMapper.writeValueAsString(allCardsResponseDTO); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(systemUtil.getEnvMap()).thenReturn(envMap); - - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - jiraBoardSetting - .setOverrideFields(List.of(TargetField.builder().key("summary").name("Story Points").flag(true).build(), - TargetField.builder().key("").name("Flagged").flag(true).build())); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getStoryPointSum()).isEqualTo(0.0); - assertThat(cardCollection.getCardsNumber()).isEqualTo(1); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsWhenStartTimeIsTooBig() throws JsonProcessingException { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - CardHistoryResponseDTO cardHistoryResponseDTO = CardHistoryResponseDTO.builder() - .isLast(true) - .items(List.of(new HistoryDetail(1, "status", new Status("To do"), new Status("Done"), null, null))) - .build(); - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - jiraBoardSetting - .setOverrideFields(List.of(TargetField.builder().key("summary").name("Story Points").flag(true).build(), - TargetField.builder().key("").name("Flagged").flag(true).build())); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", - storyPointsAndCycleTimeRequest.getStartTime(), storyPointsAndCycleTimeRequest.getEndTime()); - - Map envMap = new HashMap<>(); - envMap.put("STORY_POINT_KEY", "storyPoints"); - - AllCardsResponseDTO allCardsResponseDTO = ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build(); - allCardsResponseDTO.getIssues() - .add(JiraCard.builder() - .key("2") - .fields(JiraCardField.builder().assignee(new Assignee("Test 1")).storyPoints(0).build()) - .build()); - String allDoneCards = objectMapper.writeValueAsString(allCardsResponseDTO); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)).thenReturn(cardHistoryResponseDTO); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)).thenReturn(cardHistoryResponseDTO); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(systemUtil.getEnvMap()).thenReturn(envMap); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getStoryPointSum()).isEqualTo(0.0); - assertThat(cardCollection.getCardsNumber()).isZero(); - } - - @Test - void shouldGetCardCollection() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - - JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); - jiraBoardSetting - .setOverrideFields(List.of(TargetField.builder().key("summary").name("Story Points").flag(true).build(), - TargetField.builder().key("").name("Flagged").flag(true).build())); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() - .build(); - storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); - String allDoneCards = """ - {"total":"2","issues":[{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":5.0,"story point estimate":null,"sprint":null,"flagged":null}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":{},otherSprint:1}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":1,otherSprint:[]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":"s",otherSprint:[{"key":1}]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":{"test":1}}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":{}}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":0}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":[]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":[{"value":1}]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"Story point estimate":{"test":1},"Flagged":[null]}}]} - """; - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) - .thenReturn(ALL_FIELD_RESPONSE_CONTAIN_CUSTOMER_FIELDS().build()); - - jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(storyPointsAndCycleTimeRequest, - jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - - verify(jiraFeignClient, times(10)).getJiraCardHistoryByCount(any(), eq("1"), anyInt(), anyInt(), any()); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsRealDoneAndCycleTimeGivenStoryPointKeyFromEnvironmentVariable() - throws JsonProcessingException { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format("status in ('%s','%s') AND status changed during (%s, %s)", "Testing", "DONE", - boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - Map envMap = new HashMap<>(); - envMap.put("STORY_POINT_KEY", "customfield_10016"); - - String allDoneCards = objectMapper - .writeValueAsString(ALL_REAL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("\"storyPoints\":0", "\"customfield_10016\":null") - .replaceAll("storyPoints", "customfield_10016"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_REAL_DONE_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(CARD_HISTORY_REAL_DONE_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(systemUtil.getEnvMap()).thenReturn(envMap); - - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_REAL_DONE_CARD().build(); - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_REAL_DONE_SETTING_BUILD().build(); - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getStoryPointSum()).isEqualTo(5); - assertThat(cardCollection.getCardsNumber()).isEqualTo(1); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeGivenNotEmptyStoryPointKeyAndFlaggedFromOverrideFields() - throws JsonProcessingException { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", - boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("\"storyPoints\":0", "\"customfield_10016\":null") - .replaceAll("storyPoints", "customfield_10016"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) - .thenReturn(ALL_FIELD_RESPONSE_BUILDER_HAS_STORY_POINT().build()); - when(systemUtil.getEnvMap()).thenReturn(Map.of()); - - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - jiraBoardSetting.setOverrideFields( - List.of(TargetField.builder().key("customfield_10016").name("Story Points").flag(true).build(), - TargetField.builder().key("customfield_10017").name("Flagged").flag(true).build())); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getStoryPointSum()).isEqualTo(11); - assertThat(cardCollection.getCardsNumber()).isEqualTo(4); - } - - @Test - @Deprecated - void shouldThrowExceptionWhenGetJiraConfigurationThrowsUnExpectedException() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - when(jiraFeignClient.getJiraBoardConfiguration(any(URI.class), any(), any())) - .thenThrow(new CompletionException(new Exception("UnExpected Exception"))); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) - .isInstanceOf(InternalServerErrorException.class) - .hasMessageContaining("UnExpected Exception"); - } - - @Test - void shouldThrowExceptionWhenGetJiraInfoThrowsUnExpectedException() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - when(jiraFeignClient.getJiraBoardConfiguration(any(URI.class), any(), any())) - .thenThrow(new CompletionException(new Exception("UnExpected Exception"))); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)) - .isInstanceOf(InternalServerErrorException.class) - .hasMessageContaining("UnExpected Exception"); - } - - @Test - @Deprecated - void shouldReturnAssigneeNameFromDoneCardWhenGetAssigneeSet() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(new CardHistoryResponseDTO(true, Collections.emptyList())); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam); - - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getUsers().get(0)).isEqualTo("Zhang San"); - } - - @Test - void shouldReturnAssigneeNameFromDoneCardWhenGetBoardInfoAndGetAssigneeSet() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(new CardHistoryResponseDTO(true, Collections.emptyList())); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); - assertThat(boardConfigDTO.getUsers()).hasSize(1); - assertThat(boardConfigDTO.getUsers().get(0)).isEqualTo("Zhang San"); - } - - @Test - @Deprecated - void shouldThrowExceptionWhenGetTargetFieldFailed() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) - .thenThrow(new CustomFeignClientException(500, "exception")); - - assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(Exception.class) - .hasMessageContaining("exception"); - } - - @Test - void shouldThrowExceptionWhenGetBoardInfoAndGetTargetFieldFailed() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) - .thenThrow(new CustomFeignClientException(500, "exception")); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(Exception.class) - .hasMessageContaining("exception"); - } + @Nested + class Verify { + + @Test + void shouldReturnBoardVerifyResponseWhenVerifyJiraBoardAndCallJiraFeignClient() { + JiraBoardVerifyDTO jiraBoardVerifyDTO = JIRA_BOARD_VERIFY_RESPONSE_BUILDER().build(); + BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + doReturn(jiraBoardVerifyDTO).when(jiraFeignClient) + .getBoard(baseUrl, boardVerifyRequestParam.getBoardId(), boardVerifyRequestParam.getToken()); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + + String projectKey = jiraService.verify(BoardType.JIRA, boardVerifyRequestParam); + jiraService.shutdownExecutor(); + + assertThat(Objects.requireNonNull(projectKey)).isEqualTo("ADM"); + } + + @Test + void shouldThrowExceptionWhenBoardTypeNotCorrect() { + BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); + + assertThatThrownBy(() -> jiraService.verify(BoardType.CLASSIC_JIRA, boardVerifyRequestParam)) + .isInstanceOf(BadRequestException.class) + .hasMessageContaining("boardType param is not correct"); + } + + @Test + void shouldThrowInternalExceptionWhenCallJiraFeignClientAndNoColumn() { + JiraBoardVerifyDTO jiraBoardVerifyDTO = JIRA_BOARD_VERIFY_FAILED_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doReturn(jiraBoardVerifyDTO).when(jiraFeignClient).getBoard(baseUrl, BOARD_ID, token); + + Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); + + assertThat(thrown).isInstanceOf(InternalServerErrorException.class) + .hasMessageContaining("Failed to call Jira to verify board, cause is"); + } + + @Test + void shouldThrowBaseExceptionWhenVerifyJiraBoardGivenUnauthorizedOfCallingJiraFeignClient() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doThrow(new UnauthorizedException("")).when(jiraFeignClient) + .getBoard(baseUrl, boardVerifyRequestParam.getBoardId(), boardVerifyRequestParam.getToken()); + + Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); + + assertThat(thrown).isInstanceOf(BaseException.class); + } + + @Test + void shouldThrowNotFoundWhenVerifyJiraBoardAndBoardIdIsError() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doThrow(new NotFoundException("boardId is incorrect")).when(jiraFeignClient) + .getBoard(baseUrl, BOARD_ID, token); + + Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); + + assertThat(thrown).isInstanceOf(RuntimeException.class).hasMessageContaining("boardId is incorrect"); + } + + @Test + void shouldThrowNotFoundWhenVerifyJiraBoardSiteIsError() { + URI baseUrl = URI.create(INVALID_SITE_ATLASSIAN_NET); + BoardVerifyRequestParam boardVerifyRequestParam = BOARD_VERIFY_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(INVALID_SITE_ATLASSIAN_NET)); + doThrow(new NotFoundException("site is incorrect")).when(jiraFeignClient).getDashboard(baseUrl, token); + + Throwable thrown = catchThrowable(() -> jiraService.verify(boardTypeJira, boardVerifyRequestParam)); + + assertThat(thrown).isInstanceOf(RuntimeException.class).hasMessageContaining("site is incorrect"); + } + + } + + @Nested + class GetInfo { + + @Test + void shouldReturnBoardInfoResponseWhenGetJiraBoardInfoSuccessfully() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of( + new TargetField("customfield_10016", "Story point estimate", false), + new TargetField("customfield_10020", "Sprint", false), + new TargetField("customfield_10021", "Flagged", false)); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); + jiraService.shutdownExecutor(); + + assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)) + .isEqualTo("DOING"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + @Test + void shouldReturnBoardInfoResponseWhenGetJiraBoardInfoHasTwoPage() throws IOException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of( + new TargetField("customfield_10016", "Story point estimate", false), + new TargetField("customfield_10020", "Sprint", false), + new TargetField("customfield_10021", "Flagged", false)); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_TWO_PAGES_CARDS_RESPONSE_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 100, jql, token)) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); + + assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)) + .isEqualTo("DOING"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getTargetFields()).hasSize(3); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + @Test + void shouldReturnBoardInfoResponseSuccessfullyWhenJiraBoardStyleIsClassic() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of( + new TargetField("customfield_10016", "Story point estimate", false), + new TargetField("customfield_10020", "Sprint", false), + new TargetField("customfield_10021", "Flagged", false)); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("classic").build()); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)) + .thenReturn(completeStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); + + assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)) + .isEqualTo("DOING"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getTargetFields()).hasSize(3); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + @Test + void shouldThrowParamExceptionWhenGetJiraBoardInfoThrowBadRequest() { + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + + assertThatThrownBy(() -> jiraService.getInfo(null, boardRequestParam)) + .isInstanceOf(BadRequestException.class) + .hasMessageContaining("boardType param is not correct"); + } + + @Test + void shouldThrowNonContentExceptionWhenGetJiraBoardInfoAndJiraBoardIsNoCards() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)) + .thenReturn(objectMapper.writeValueAsString(ONE_PAGE_NO_DONE_CARDS_RESPONSE_BUILDER().build())); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)) + .isInstanceOf(NoContentException.class) + .hasMessageContaining("There is no cards."); + } + + @Test + void shouldThrowInternalExceptionWhenGetJiraCardsReturnNull() { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO noneStatusSelf = NONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(noneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + Throwable thrown = catchThrowable(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)); + + assertThat(thrown).isInstanceOf(InternalServerErrorException.class) + .hasMessageContaining("Failed to call Jira to get board info, cause is"); + } + + @Test + void shouldThrowExceptionWhenGetJiraInfoThrowsUnExpectedException() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(jiraFeignClient.getJiraBoardConfiguration(any(URI.class), any(), any())) + .thenThrow(new CompletionException(new Exception("UnExpected Exception"))); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)) + .isInstanceOf(InternalServerErrorException.class) + .hasMessageContaining("UnExpected Exception"); + } + + @Test + void shouldReturnAssigneeNameFromDoneCardWhenGetBoardInfoAndGetAssigneeSet() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(new CardHistoryResponseDTO(true, Collections.emptyList())); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); + + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getUsers().get(0)).isEqualTo("Zhang San"); + } + + @Test + void shouldThrowExceptionWhenGetBoardInfoAndGetTargetFieldFailed() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) + .thenThrow(new CustomFeignClientException(500, "exception")); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) + .isInstanceOf(Exception.class) + .hasMessageContaining("exception"); + } + + @Test + void shouldThrowExceptionWhenGetBoardInfoAndGetTargetFieldReturnNull() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)).thenReturn(null); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) + .isInstanceOf(PermissionDenyException.class) + .hasMessageContaining("There is no enough permission."); + } + + @Test + void shouldThrowExceptionWhenGetBoardInfoAndGetTargetFieldReturnEmpty() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + FieldResponseDTO emptyProjectFieldResponse = FieldResponseDTO.builder() + .projects(Collections.emptyList()) + .build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) + .thenReturn(emptyProjectFieldResponse); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) + .isInstanceOf(PermissionDenyException.class) + .hasMessageContaining("There is no enough permission."); + } + + @Test + void shouldThrowCustomExceptionWhenGetTargetFieldIsNull() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) + .isInstanceOf(PermissionDenyException.class) + .hasMessageContaining("There is no enough permission."); + } + + @Test + void shouldThrowCustomExceptionWhenCallJiraFeignClientToGetBoardInfoFailed() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BoardRequestParam.builder().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("next-gen").build()); + when(jiraFeignClient.getJiraBoardConfiguration(any(), any(), any())) + .thenThrow(new CustomFeignClientException(400, "exception")); + when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)) + .isInstanceOf(InternalServerErrorException.class) + .hasMessageContaining("exception"); + } + + @Test + void shouldReturnBadRequestExceptionWhenBoardStyleIsNotCorrect() { + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(jiraFeignClient.getProject(any(), any(), any())) + .thenReturn(JiraBoardProject.builder().style("unknown").build()); + + assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)) + .isInstanceOf(InternalServerErrorException.class) + .hasMessageContaining("Board type does not find!"); + } + + @Test + void shouldFilterOutUnreasonableTargetFieldWhenGetBoardInfo() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of(new TargetField("customfield_10021", "Flagged", false), + new TargetField("priority", "Priority", false), + new TargetField("timetracking", "Time tracking", false)); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getProject(baseUrl, "project key", token)) + .thenReturn(JiraBoardProject.builder().style("classic").build()); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)) + .thenReturn(completeStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(INCLUDE_UNREASONABLE_FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); + + assertThat(boardConfigDTO.getTargetFields()).hasSize(3); + assertThat(boardConfigDTO.getTargetFields()) + .doesNotContain(new TargetField("customfield_10000", "Development", false)); + assertThat(boardConfigDTO.getTargetFields().contains(new TargetField("customfield_10019", "Rank", false))) + .isFalse(); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + } + + @Nested + class GetJiraConfiguration { + + @Test + @Deprecated + void shouldReturnBoardConfigResponseSuccessfullyWhenGetJiraBoardConfig() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of( + new TargetField("customfield_10016", "Story point estimate", false), + new TargetField("customfield_10020", "Sprint", false), + new TargetField("customfield_10021", "Flagged", false)); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam); + jiraService.shutdownExecutor(); + + assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)) + .isEqualTo("DOING"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + @Test + @Deprecated + void shouldReturnBoardConfigResponseSuccessfullyWhenGetJiraBoardConfigHasTwoPage() throws IOException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of( + new TargetField("customfield_10016", "Story point estimate", false), + new TargetField("customfield_10020", "Sprint", false), + new TargetField("customfield_10021", "Flagged", false)); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_TWO_PAGES_CARDS_RESPONSE_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 100, jql, token)) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam); + + assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)) + .isEqualTo("DOING"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getTargetFields()).hasSize(3); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + @Test + @Deprecated + void shouldReturnBoardConfigResponseSuccessfullyWhenJiraBoardConfigIsClassic() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of( + new TargetField("customfield_10016", "Story point estimate", false), + new TargetField("customfield_10020", "Sprint", false), + new TargetField("customfield_10021", "Flagged", false)); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)) + .thenReturn(completeStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeClassicJira, boardRequestParam); + + assertThat(boardConfigDTO.getJiraColumnResponse()).hasSize(1); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getName()).isEqualTo("TODO"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(0)).isEqualTo("DONE"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getValue().getStatuses().get(1)) + .isEqualTo("DOING"); + assertThat(boardConfigDTO.getJiraColumnResponse().get(0).getKey()).isEqualTo("done"); + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getTargetFields()).hasSize(3); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + @Test + @Deprecated + void shouldThrowParamExceptionWhenGetJiraBoardInfoThrowBadRequest() { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(null, boardRequestParam)) + .isInstanceOf(BadRequestException.class) + .hasMessageContaining("boardType param is not correct"); + } + + @Test + @Deprecated + void shouldReturnBoardConfigResponseSuccessfullyWhenGetColumnStatusCategoryThrowNotFoundException() + throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)) + .thenThrow(new NotFoundException("message")); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(new CardHistoryResponseDTO(true, Collections.emptyList())); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatCode(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .doesNotThrowAnyException(); + } + + @Test + @Deprecated + void shouldThrowNonContentExceptionWhenGetJiraBoardConfigIsNoCards() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)) + .thenReturn(objectMapper.writeValueAsString(ONE_PAGE_NO_DONE_CARDS_RESPONSE_BUILDER().build())); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .isInstanceOf(NoContentException.class) + .hasMessageContaining("There is no cards."); + } + + @Test + @Deprecated + void shouldThrowInternalExceptionWhenGetJiraCardsReturnNull() { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO noneStatusSelf = NONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(noneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + Throwable thrown = catchThrowable(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)); + + assertThat(thrown).isInstanceOf(InternalServerErrorException.class) + .hasMessageContaining("Failed to call Jira to get board config, cause is"); + } + + @Test + @Deprecated + void shouldThrowExceptionWhenGetJiraConfigurationThrowsUnExpectedException() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(jiraFeignClient.getJiraBoardConfiguration(any(URI.class), any(), any())) + .thenThrow(new CompletionException(new Exception("UnExpected Exception"))); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .isInstanceOf(InternalServerErrorException.class) + .hasMessageContaining("UnExpected Exception"); + } + + @Test + @Deprecated + void shouldReturnAssigneeNameFromDoneCardWhenGetAssigneeSet() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(new CardHistoryResponseDTO(true, Collections.emptyList())); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam); + + assertThat(boardConfigDTO.getUsers()).hasSize(1); + assertThat(boardConfigDTO.getUsers().get(0)).isEqualTo("Zhang San"); + } + + @Test + @Deprecated + void shouldThrowExceptionWhenGetTargetFieldFailed() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) + .thenThrow(new CustomFeignClientException(500, "exception")); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .isInstanceOf(Exception.class) + .hasMessageContaining("exception"); + } + + @Test + @Deprecated + void shouldThrowExceptionWhenGetTargetFieldReturnNull() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)).thenReturn(null); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .isInstanceOf(PermissionDenyException.class) + .hasMessageContaining("There is no enough permission."); + } + + @Test + @Deprecated + void shouldThrowExceptionWhenGetTargetFieldReturnEmpty() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + FieldResponseDTO emptyProjectFieldResponse = FieldResponseDTO.builder() + .projects(Collections.emptyList()) + .build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) + .thenReturn(emptyProjectFieldResponse); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .isInstanceOf(PermissionDenyException.class) + .hasMessageContaining("There is no enough permission."); + } + + @Test + @Deprecated + void shouldThrowCustomExceptionWhenGetTargetFieldIsNull() { + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .isInstanceOf(PermissionDenyException.class) + .hasMessageContaining("There is no enough permission."); + } + + @Test + @Deprecated + void shouldThrowCustomExceptionWhenCallJiraFeignClientToGetBoardConfigFailed() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BoardRequestParam.builder().build(); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getJiraBoardConfiguration(any(), any(), any())) + .thenThrow(new CustomFeignClientException(400, "exception")); + when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) + .thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, boardRequestParam)) + .isInstanceOf(Exception.class) + .hasMessageContaining("exception"); + } + + @Test + @Deprecated + void shouldFilterOutUnreasonableTargetField() throws JsonProcessingException { + JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); + StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + List expectTargetField = List.of(new TargetField("customfield_10021", "Flagged", false), + new TargetField("priority", "Priority", false), + new TargetField("timetracking", "Time tracking", false)); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); + when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)) + .thenReturn(completeStatusSelf); + when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) + .thenReturn(INCLUDE_UNREASONABLE_FIELD_RESPONSE_BUILDER().build()); + + BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeClassicJira, boardRequestParam); + + assertThat(boardConfigDTO.getTargetFields()).hasSize(3); + assertThat(boardConfigDTO.getTargetFields()) + .doesNotContain(new TargetField("customfield_10000", "Development", false)); + assertThat(boardConfigDTO.getTargetFields().contains(new TargetField("customfield_10019", "Rank", false))) + .isFalse(); + assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); + } + + } + + @Nested + class GetStoryPointsAndCycleTimeAndReworkInfoForDoneCards { + + @Test + void shouldCallJiraFeignClientTwiceGivenTwoPageHistoryDataWhenGetJiraBoardConfig() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() + .build(); + String allDoneCards = objectMapper.writeValueAsString(NEED_FILTERED_ALL_DONE_CARDS_BUILDER().build()); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(new CardHistoryResponseDTO(false, new ArrayList<>(List + .of(new HistoryDetail(1, "status", new Status("To do"), new Status("Block"), null, null))))); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 100, 100, token)) + .thenReturn(new CardHistoryResponseDTO(true, new ArrayList<>(List + .of(new HistoryDetail(2, "assignee", new Status("In Dev"), new Status("To do"), null, null))))); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - @Test - @Deprecated - void shouldThrowExceptionWhenGetTargetFieldReturnNull() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)).thenReturn(null); - - assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(PermissionDenyException.class) - .hasMessageContaining("There is no enough permission."); - } - - @Test - void shouldThrowExceptionWhenGetBoardInfoAndGetTargetFieldReturnNull() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)).thenReturn(null); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(PermissionDenyException.class) - .hasMessageContaining("There is no enough permission."); - } - - @Test - @Deprecated - void shouldThrowExceptionWhenGetTargetFieldReturnEmpty() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - FieldResponseDTO emptyProjectFieldResponse = FieldResponseDTO.builder() - .projects(Collections.emptyList()) - .build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) - .thenReturn(emptyProjectFieldResponse); - - assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(PermissionDenyException.class) - .hasMessageContaining("There is no enough permission."); - } - - @Test - void shouldThrowExceptionWhenGetBoardInfoAndGetTargetFieldReturnEmpty() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - FieldResponseDTO emptyProjectFieldResponse = FieldResponseDTO.builder() - .projects(Collections.emptyList()) - .build(); - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getTargetField(baseUrl, boardRequestParam.getProjectKey(), token)) - .thenReturn(emptyProjectFieldResponse); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(PermissionDenyException.class) - .hasMessageContaining("There is no enough permission."); - } - - @Test - @Deprecated - void shouldThrowCustomExceptionWhenGetJiraBoardConfig() { - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - - assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(PermissionDenyException.class) - .hasMessageContaining("There is no enough permission."); - } - - @Test - void shouldThrowCustomExceptionWhenGetJiraBoardInfo() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BOARD_REQUEST_BUILDER().build())) - .isInstanceOf(PermissionDenyException.class) - .hasMessageContaining("There is no enough permission."); - } - - @Test - @Deprecated - void shouldThrowCustomExceptionWhenCallJiraFeignClientToGetBoardConfigFailed() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getJiraBoardConfiguration(any(), any(), any())) - .thenThrow(new CustomFeignClientException(400, "exception")); - when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - assertThatThrownBy(() -> jiraService.getJiraConfiguration(boardTypeJira, BoardRequestParam.builder().build())) - .isInstanceOf(Exception.class) - .hasMessageContaining("exception"); - } - - @Test - void shouldThrowCustomExceptionWhenCallJiraFeignClientToGetBoardInfoFailed() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("next-gen").build()); - when(jiraFeignClient.getJiraBoardConfiguration(any(), any(), any())) - .thenThrow(new CustomFeignClientException(400, "exception")); - when(jiraFeignClient.getTargetField(baseUrl, "project key", "token")) - .thenReturn(FIELD_RESPONSE_BUILDER().build()); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, BoardRequestParam.builder().build())) - .isInstanceOf(Exception.class) - .hasMessageContaining("exception"); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsAndCycleTime() throws JsonProcessingException { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", - boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("\"storyPoints\":0", "\"customfield_10016\":null") - .replaceAll("storyPoints", "customfield_10016"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getStoryPointSum()).isEqualTo(0); - assertThat(cardCollection.getCardsNumber()).isEqualTo(1); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeWhenBoardTypeIsClassicJira() throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - - JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() - .build(); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getCardsNumber()).isEqualTo(0); - } - - @Test - void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeWhenDoneTimeGreaterThanSelectedEndTime() - throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - - JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() - .build(); - String allDoneCards = objectMapper.writeValueAsString(NEED_FILTERED_ALL_DONE_CARDS_BUILDER().build()); - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) - .thenReturn(CARD_HISTORY_DONE_TIME_GREATER_THAN_END_TIME_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getCardsNumber()).isEqualTo(0); - } - - @Test - void shouldReturnBadRequestExceptionWhenBoardTypeIsNotCorrect() { - - JiraBoardSetting jiraBoardSetting = INCORRECT_JIRA_BOARD_SETTING_BUILD().build(); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = INCORRECT_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() - .build(); - - List boardColumns = jiraBoardSetting.getBoardColumns(); - List users = List.of("Zhang San"); - ZoneId zoneId = ZoneId.of("Asia/Shanghai"); - assertThatThrownBy(() -> jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, boardColumns, users, null, CalendarTypeEnum.REGULAR, zoneId)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Board type does not find!"); - } - - @Test - void shouldReturnBadRequestExceptionWhenBoardStyleIsNotCorrect() { - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - - when(jiraFeignClient.getProject(any(), any(), any())) - .thenReturn(JiraBoardProject.builder().style("unknown").build()); - - assertThatThrownBy(() -> jiraService.getInfo(boardTypeJira, boardRequestParam)) - .isInstanceOf(InternalServerErrorException.class) - .hasMessageContaining("Board type does not find!"); - } - - @Test - public void shouldProcessCustomFieldsForCardsWhenCallGetStoryPointsAndCycleTime() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn( - "{\"total\":1,\"issues\":[{\"expand\":\"expand\",\"id\":\"1\",\"self\":\"https:xxxx/issue/1\",\"key\":\"ADM-455\",\"fields\":{\"customfield_10020\":[{\"id\":16,\"name\":\"Tool Sprint 11\",\"state\":\"closed\",\"boardId\":2,\"goal\":\"goals\",\"startDate\":\"2023-05-15T03:09:23.000Z\",\"endDate\":\"2023-05-28T16:00:00.000Z\",\"completeDate\":\"2023-05-29T03:51:24.898Z\"}],\"customfield_10021\":[{\"self\":\"https:xxxx/10019\",\"value\":\"Impediment\",\"id\":\"10019\"}],\"customfield_10016\":1,\"assignee\":{\"displayName\":\"Zhang San\"}}}]}"); - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(FIELD_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(boardUtil.getCycleTimeInfos(any(), any(), any(), any(), any())).thenReturn(CYCLE_TIME_INFO_LIST()); - when(boardUtil.getOriginCycleTimeInfos(any(), any(), any(), any())).thenReturn(CYCLE_TIME_INFO_LIST()); - - CardCollection doneCards = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - assertThat(doneCards.getStoryPointSum()).isEqualTo(1); - assertThat(doneCards.getCardsNumber()).isEqualTo(1); - } - - @Test - public void shouldReturnNullWhenCallGetStoryPointsAndCycleTimeAndHistoryISNull() { - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn( - "{\"total\":1,\"issues\":[{\"expand\":\"expand\",\"id\":\"1\",\"self\":\"https:xxxx/issue/1\",\"key\":\"ADM-455\",\"fields\":{\"customfield_10020\":[{\"id\":16,\"name\":\"Tool Sprint 11\",\"state\":\"closed\",\"boardId\":2,\"goal\":\"goals\",\"startDate\":\"2023-05-15T03:09:23.000Z\",\"endDate\":\"2023-05-28T16:00:00.000Z\",\"completeDate\":\"2023-05-29T03:51:24.898Z\"}],\"customfield_10021\":[{\"self\":\"https:xxxx/10019\",\"value\":\"Impediment\",\"id\":\"10019\"}],\"customfield_10016\":1,\"assignee\":{\"displayName\":\"Zhang San\"}}}]}"); - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(FIELD_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER_TO_DONE().build()); - - CardCollection doneCards = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), null, - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - assertThat(doneCards.getStoryPointSum()).isEqualTo(0); - assertThat(doneCards.getCardsNumber()).isEqualTo(0); - } - - @Test - void shouldReturnIllegalArgumentExceptionWhenHaveUnknownColumn() throws JsonProcessingException { - String token = "token"; - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_HAVE_UNKNOWN_COLUMN_BUILD().build(); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().startTime("5") - .build(); - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().startTime("5").build(); - String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", - boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(FIELD_RESPONSE_BUILDER().build()); - - List boardColumns = jiraBoardSetting.getBoardColumns(); - List users = List.of("Zhang San"); - ZoneId zoneId = ZoneId.of("Asia/Shanghai"); - assertThatThrownBy(() -> { jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(storyPointsAndCycleTimeRequest, - boardColumns, users, null, CalendarTypeEnum.REGULAR, zoneId); - }).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("Type does not find!"); - } - - @Test - public void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForActiveSprint() - throws JsonProcessingException { - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())) - .thenReturn(objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); - assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); - } - - @Test - void shouldReturnCardsWhenCallGetStoryPointsWhenAssigneeIsNull() throws JsonProcessingException { - String assignName = "Zhang San"; - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - - CardHistoryResponseDTO cardHistoryResponseDTO = CardHistoryResponseDTO.builder() - .isLast(true) - .items(List.of(new HistoryDetail(1, "assignee", Status.builder().name("nonToDisplay").build(), - Status.builder().name("nonFromDisplay").build(), null, null))) - .build(); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - AllCardsResponseDTO allCardsResponseDTO = AllCardsResponseDTO.builder() - .total("3") - .issues(List.of( - new JiraCard("1", - JiraCardField.builder() - .assignee(new Assignee(assignName)) - .issuetype(IssueType.builder().name("缺陷").build()) - .storyPoints(2) - .status(new Status(CardStepsEnum.TESTING.getValue())) - .build()), - new JiraCard("2", - JiraCardField.builder() - .issuetype(IssueType.builder().name("缺陷").build()) - .storyPoints(2) - .status(new Status(CardStepsEnum.TESTING.getValue())) - .build()), - new JiraCard("3", - JiraCardField.builder() - .assignee(Assignee.builder().build()) - .issuetype(IssueType.builder().name("缺陷").build()) - .storyPoints(2) - .status(new Status(CardStepsEnum.TESTING.getValue())) - .build()))) - .build(); - - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())) - .thenReturn(objectMapper.writeValueAsString(allCardsResponseDTO)); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(cardHistoryResponseDTO); - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - assertThat(nonDoneCards.getStoryPointSum()).isZero(); - assertThat(nonDoneCards.getCardsNumber()).isEqualTo(1); - } - - @Test - void shouldReturnCardsWhenCallGetStoryPointsWhenHistoryItemIsEmpty() throws JsonProcessingException { - String assignName = "Zhang San"; - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - HashMap issueFieldMap = new HashMap<>(); - FieldResponseDTO targetField = FieldResponseDTO.builder() - .projects(List.of(new Project(List.of(new Issuetype(issueFieldMap))))) - .build(); - - CardHistoryResponseDTO cardHistoryResponseDTO = CardHistoryResponseDTO.builder() - .isLast(true) - .items(List.of()) - .build(); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - AllCardsResponseDTO allCardsResponseDTO = AllCardsResponseDTO.builder() - .total("3") - .issues(List.of( - new JiraCard("1", - JiraCardField.builder() - .assignee(new Assignee(assignName)) - .issuetype(IssueType.builder().name("缺陷").build()) - .storyPoints(2) - .status(new Status(CardStepsEnum.TESTING.getValue())) - .build()), - new JiraCard("2", - JiraCardField.builder() - .issuetype(IssueType.builder().name("缺陷").build()) - .storyPoints(2) - .status(new Status(CardStepsEnum.TESTING.getValue())) - .build()), - new JiraCard("3", - JiraCardField.builder() - .assignee(Assignee.builder().build()) - .issuetype(IssueType.builder().name("缺陷").build()) - .storyPoints(2) - .status(new Status(CardStepsEnum.TESTING.getValue())) - .build()))) - .build(); - - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())) - .thenReturn(objectMapper.writeValueAsString(allCardsResponseDTO)); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(cardHistoryResponseDTO); - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(targetField); - - CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - assertThat(nonDoneCards.getStoryPointSum()).isZero(); - assertThat(nonDoneCards.getCardsNumber()).isEqualTo(1); - } - - @Test - void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForActiveSprintWithStatusIsEmpty() - throws JsonProcessingException { - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD_WITH_EMPTY_STATUS() - .build(); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())) - .thenReturn(objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - - CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); - assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); - } - - @Test - public void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForKanban() - throws JsonProcessingException { - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jqlForKanban = "status not in ('" + String.join("','", storyPointsAndCycleTimeRequest.getStatus()) - + "') ORDER BY updated DESC"; - String jqlForActiveSprint = "sprint in openSprints() AND status not in ('" - + String.join("','", storyPointsAndCycleTimeRequest.getStatus()) + "') ORDER BY updated DESC"; - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForActiveSprint, - boardRequestParam.getToken())) - .thenReturn(""); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForKanban, - boardRequestParam.getToken())) - .thenReturn(objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); - - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - - CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); - assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); - } - - @Test - public void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForKanbanWithStatusIsEmpty() - throws JsonProcessingException { - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD_WITH_EMPTY_STATUS() - .build(); - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jqlForKanban = "ORDER BY updated DESC"; - String jqlForActiveSprint = "sprint in openSprints() ORDER BY updated DESC"; - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForActiveSprint, - boardRequestParam.getToken())) - .thenReturn(""); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForKanban, - boardRequestParam.getToken())) - .thenReturn(objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); - - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - - CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); - assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); - } - - @Test - void shouldReturnCardsWithSprintWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForKanbanWithStatusIsEmpty() { - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD_WITH_EMPTY_STATUS() - .build(); - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jqlForActiveSprint = "sprint in openSprints() ORDER BY updated DESC"; - String allDoneCards = JiraBoardConfigDTOFixture.JIRA_CARD_WITH_TWO_SPRINT; - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForActiveSprint, - boardRequestParam.getToken())) - .thenReturn(allDoneCards); - when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); - - CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( - storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); - assertThat(nonDoneCards.getCardsNumber()).isEqualTo(1); - assertThat(nonDoneCards.getJiraCardDTOList().get(0).getBaseInfo().getFields().getSprint().getName()) - .isEqualTo("TS Sprint 1"); - } - - @Test - public void shouldReturnJiraBoardConfigDTOWhenCallGetJiraBoardConfig() { - String token = "token"; - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - JiraBoardConfigDTO mockResponse = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - - when(jiraFeignClient.getJiraBoardConfiguration(any(), any(), any())).thenReturn(mockResponse); - JiraBoardConfigDTO result = jiraService.getJiraBoardConfig(baseUrl, BOARD_ID, token); - - assertThat(mockResponse).isEqualTo(result); - } + jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", CalendarTypeEnum.REGULAR, zoneId); + + verify(jiraFeignClient, times(2)).getJiraCardHistoryByCount(any(), eq("2"), anyInt(), anyInt(), any()); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeGivenStoryPointKeyFromEnvironmentVariable() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", + boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + Map envMap = new HashMap<>(); + envMap.put("STORY_POINT_KEY", "customfield_10016"); + AllCardsResponseDTO allCardsResponseDTO = ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build(); + String allDoneCards = objectMapper.writeValueAsString(allCardsResponseDTO) + .replaceAll("\"storyPoints\":5.0", "\"customfield_10016\":null") + .replaceAll("storyPoints", "customfield_10016"); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + jiraBoardSetting + .setOverrideFields(List.of(TargetField.builder().key("").name("Story Points").flag(true).build(), + TargetField.builder().key("").name("Flagged").flag(true).build())); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(systemUtil.getEnvMap()).thenReturn(envMap); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getStoryPointSum()).isEqualTo(6.0); + assertThat(cardCollection.getCardsNumber()).isEqualTo(4); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeGivenStoryPointKeyFromEnvironmentVariableWhenTargetFieldIsTrue() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", + boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + Map envMap = new HashMap<>(); + envMap.put("STORY_POINT_KEY", "storyPoints"); + AllCardsResponseDTO allCardsResponseDTO = ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build(); + allCardsResponseDTO.getIssues() + .add(JiraCard.builder() + .key("2") + .fields(JiraCardField.builder().assignee(new Assignee("Test 1")).storyPoints(0).build()) + .build()); + String allDoneCards = objectMapper.writeValueAsString(allCardsResponseDTO); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + jiraBoardSetting + .setOverrideFields(List.of(TargetField.builder().key("summary").name("Story Points").flag(true).build(), + TargetField.builder().key("").name("Flagged").flag(true).build())); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(systemUtil.getEnvMap()).thenReturn(envMap); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getStoryPointSum()).isEqualTo(0.0); + assertThat(cardCollection.getCardsNumber()).isEqualTo(1); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsWhenStartTimeIsTooBig() throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + CardHistoryResponseDTO cardHistoryResponseDTO = CardHistoryResponseDTO.builder() + .isLast(true) + .items(List.of(new HistoryDetail(1, "status", new Status("To do"), new Status("Done"), null, null))) + .build(); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + jiraBoardSetting + .setOverrideFields(List.of(TargetField.builder().key("summary").name("Story Points").flag(true).build(), + TargetField.builder().key("").name("Flagged").flag(true).build())); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", + storyPointsAndCycleTimeRequest.getStartTime(), storyPointsAndCycleTimeRequest.getEndTime()); + Map envMap = new HashMap<>(); + envMap.put("STORY_POINT_KEY", "storyPoints"); + AllCardsResponseDTO allCardsResponseDTO = ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build(); + allCardsResponseDTO.getIssues() + .add(JiraCard.builder() + .key("2") + .fields(JiraCardField.builder().assignee(new Assignee("Test 1")).storyPoints(0).build()) + .build()); + String allDoneCards = objectMapper.writeValueAsString(allCardsResponseDTO); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(cardHistoryResponseDTO); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(cardHistoryResponseDTO); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(systemUtil.getEnvMap()).thenReturn(envMap); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getStoryPointSum()).isEqualTo(0.0); + assertThat(cardCollection.getCardsNumber()).isZero(); + } + + @Test + void shouldGetCardCollection() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); + jiraBoardSetting + .setOverrideFields(List.of(TargetField.builder().key("summary").name("Story Points").flag(true).build(), + TargetField.builder().key("").name("Flagged").flag(true).build())); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() + .build(); + storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); + String allDoneCards = """ + {"total":"2","issues":[{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":5.0,"story point estimate":null,"sprint":null,"flagged":null}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":{},otherSprint:1}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":1,otherSprint:[]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":"s",otherSprint:[{"key":1}]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"story point estimate":{"test":1}}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":{}}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":0}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":[]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"flagged":[{"value":1}]}},{"key":"1","fields":{"assignee":{"displayName":"Zhang San"},"storyPoints":1.0,"Story point estimate":{"test":1},"Flagged":[null]}}]} + """; + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_CONTAIN_CUSTOMER_FIELDS().build()); - @Test - void shouldGetRealDoneCardGivenCallGetStoryPointsAndCycleTimeWhenUseHistoricalAssigneeFilter() - throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = AssigneeFilterMethod.HISTORICAL_ASSIGNEE.getDescription(); - - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_ASSIGNEE_FILTER_METHOD().build(); - - // return value - String allDoneCards = objectMapper - .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_ASSIGNEE_FILTER_TEST().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD1_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD2_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-520", 0, 100, token)) - .thenReturn(CARD3_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection1 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - CardCollection cardCollection2 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of("song"), assigneeFilter, CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection1.getCardsNumber()).isEqualTo(0); - assertThat(cardCollection2.getCardsNumber()).isEqualTo(1); - assertThat(cardCollection2.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-475"); - - } - - @Test - void shouldGetRealDoneCardGivenCallGetStoryPointsAndCycleTimeWhenUseLastAssigneeFilter() - throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = AssigneeFilterMethod.LAST_ASSIGNEE.getDescription(); - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_ASSIGNEE_FILTER_METHOD().build(); - - // return value - String allDoneCards = objectMapper - .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_ASSIGNEE_FILTER_TEST().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD1_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD2_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-520", 0, 100, token)) - .thenReturn(CARD3_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection1 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of("yun"), assigneeFilter, CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - CardCollection cardCollection2 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection1.getCardsNumber()).isEqualTo(1); - assertThat(cardCollection1.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-520"); - assertThat(cardCollection2.getCardsNumber()).isEqualTo(1); - assertThat(cardCollection2.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-475"); - } - - @Test - @Deprecated - void shouldFilterOutUnreasonableTargetField() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of(new TargetField("customfield_10021", "Flagged", false), - new TargetField("priority", "Priority", false), - new TargetField("timetracking", "Time tracking", false)); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)).thenReturn(completeStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(INCLUDE_UNREASONABLE_FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getJiraConfiguration(boardTypeClassicJira, boardRequestParam); - - assertThat(boardConfigDTO.getTargetFields()).hasSize(3); - assertThat( - boardConfigDTO.getTargetFields().contains(new TargetField("customfield_10000", "Development", false))) - .isFalse(); - assertThat(boardConfigDTO.getTargetFields().contains(new TargetField("customfield_10019", "Rank", false))) - .isFalse(); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - void shouldFilterOutUnreasonableTargetFieldWhenGetBoardInfo() throws JsonProcessingException { - JiraBoardConfigDTO jiraBoardConfigDTO = CLASSIC_JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); - StatusSelfDTO doneStatusSelf = DONE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO completeStatusSelf = COMPLETE_STATUS_SELF_RESPONSE_BUILDER().build(); - StatusSelfDTO doingStatusSelf = DOING_STATUS_SELF_RESPONSE_BUILDER().build(); - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); - String jql = String.format(ALL_CARDS_JQL, boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); - List expectTargetField = List.of(new TargetField("customfield_10021", "Flagged", false), - new TargetField("priority", "Priority", false), - new TargetField("timetracking", "Time tracking", false)); - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) - .replaceAll("storyPoints", "customfield_10016"); - - doReturn(jiraBoardConfigDTO).when(jiraFeignClient).getJiraBoardConfiguration(baseUrl, BOARD_ID, token); - when(urlGenerator.getUri(any())).thenReturn(URI.create(SITE_ATLASSIAN_NET)); - when(jiraFeignClient.getProject(baseUrl, "project key", token)) - .thenReturn(JiraBoardProject.builder().style("classic").build()); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_1, token)).thenReturn(doneStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_3, token)).thenReturn(completeStatusSelf); - when(jiraFeignClient.getColumnStatusCategory(baseUrl, COLUM_SELF_ID_2, token)).thenReturn(doingStatusSelf); - when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, token)).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) - .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); - when(jiraFeignClient.getTargetField(baseUrl, "project key", token)) - .thenReturn(INCLUDE_UNREASONABLE_FIELD_RESPONSE_BUILDER().build()); - - BoardConfigDTO boardConfigDTO = jiraService.getInfo(boardTypeJira, boardRequestParam); - assertThat(boardConfigDTO.getTargetFields()).hasSize(3); - assertThat( - boardConfigDTO.getTargetFields().contains(new TargetField("customfield_10000", "Development", false))) - .isFalse(); - assertThat(boardConfigDTO.getTargetFields().contains(new TargetField("customfield_10019", "Rank", false))) - .isFalse(); - assertThat(boardConfigDTO.getTargetFields()).isEqualTo(expectTargetField); - } - - @Test - void shouldGetRealDoneCardsGivenMultipleStatuesMappingToDoneStatusWhenCallGetStoryPointsAndCycleTime() - throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = "lastAssignee"; - - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES().build(); - - // return value - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getCardsNumber()).isEqualTo(1); - assertThat(cardCollection.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-475"); - } - - @Test - void shouldGetRealDoneCardsGivenHistoryWithNoStatusFieldWhenCallGetStoryPointsAndCycleTime() - throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = "lastAssignee"; - - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES().build(); - - // return value - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD_HISTORY_WITH_NO_STATUS_FIELD().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, - ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getCardsNumber()).isZero(); - } - - @Test - void shouldGetRealDoneCardsReworkToInDevTimesGivenNotConsiderFlagIsBlockAndNoExclude() - throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = "lastAssignee"; - - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() - .treatFlagCardAsBlock(false) - .reworkTimesSetting(ReworkTimesSetting.builder().reworkState("In Dev").excludedStates(List.of()).build()) - .build(); - - // return value - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD3_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), - List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE, JiraBoardConfigDTOFixture.DISPLAY_NAME_TWO), - assigneeFilter, CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getReworkCardNumber()).isEqualTo(1); - assertThat(cardCollection.getReworkRatio()).isEqualTo(0.5); - assertThat(cardCollection.getJiraCardDTOList().get(0).getTotalReworkTimes()).isEqualTo(3); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) - .isEqualTo(CardStepsEnum.BLOCK); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getTimes()).isEqualTo(1); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getState()) - .isEqualTo(CardStepsEnum.REVIEW); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getTimes()).isEqualTo(1); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(3).getState()) - .isEqualTo(CardStepsEnum.TESTING); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(3).getTimes()).isEqualTo(1); - } - - @Test - void shouldGetRealDoneCardsReworkTimesToInDevGivenConsiderFlagAsBlock() throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = "lastAssignee"; - - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() - .treatFlagCardAsBlock(true) - .reworkTimesSetting(ReworkTimesSetting.builder().reworkState("In Dev").excludedStates(List.of()).build()) - .build(); - - // return value - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES_WITH_FLAG().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE), assigneeFilter, - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getReworkCardNumber()).isEqualTo(1); - assertThat(cardCollection.getReworkRatio()).isEqualTo(1); - assertThat(cardCollection.getJiraCardDTOList().get(0).getTotalReworkTimes()).isEqualTo(2); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) - .isEqualTo(CardStepsEnum.BLOCK); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getTimes()).isEqualTo(2); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) - .isEqualTo(CardStepsEnum.BLOCK); - } - - @Test - void shouldGetRealDoneCardsReworkToInDevTimesGivenNotConsiderFlagIsBlockAndExcludeState() - throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = "lastAssignee"; - - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() - .treatFlagCardAsBlock(false) - .reworkTimesSetting( - ReworkTimesSetting.builder().reworkState("In Dev").excludedStates(List.of("Block")).build()) - .build(); - - // return value - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD3_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), - List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE, JiraBoardConfigDTOFixture.DISPLAY_NAME_TWO), - assigneeFilter, CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getReworkCardNumber()).isEqualTo(1); - assertThat(cardCollection.getReworkRatio()).isEqualTo(0.5); - assertThat(cardCollection.getJiraCardDTOList().get(0).getTotalReworkTimes()).isEqualTo(2); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) - .isEqualTo(CardStepsEnum.REVIEW); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getTimes()).isEqualTo(1); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getState()) - .isEqualTo(CardStepsEnum.WAITING); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getTimes()).isZero(); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(2).getState()) - .isEqualTo(CardStepsEnum.TESTING); - assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(2).getTimes()).isEqualTo(1); - } + jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(storyPointsAndCycleTimeRequest, + jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", CalendarTypeEnum.REGULAR, zoneId); + + verify(jiraFeignClient, times(10)).getJiraCardHistoryByCount(any(), eq("1"), anyInt(), anyInt(), any()); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsRealDoneAndCycleTimeGivenStoryPointKeyFromEnvironmentVariable() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format("status in ('%s','%s') AND status changed during (%s, %s)", "Testing", "DONE", + boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + Map envMap = new HashMap<>(); + envMap.put("STORY_POINT_KEY", "customfield_10016"); + String allDoneCards = objectMapper + .writeValueAsString(ALL_REAL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("\"storyPoints\":0", "\"customfield_10016\":null") + .replaceAll("storyPoints", "customfield_10016"); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_REAL_DONE_CARD() + .build(); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_REAL_DONE_SETTING_BUILD().build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_REAL_DONE_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(CARD_HISTORY_REAL_DONE_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(systemUtil.getEnvMap()).thenReturn(envMap); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getStoryPointSum()).isEqualTo(5); + assertThat(cardCollection.getCardsNumber()).isEqualTo(1); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeGivenNotEmptyStoryPointKeyAndFlaggedFromOverrideFields() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", + boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("\"storyPoints\":0", "\"customfield_10016\":null") + .replaceAll("storyPoints", "customfield_10016"); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + jiraBoardSetting.setOverrideFields( + List.of(TargetField.builder().key("customfield_10016").name("Story Points").flag(true).build(), + TargetField.builder().key("customfield_10017").name("Flagged").flag(true).build())); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + storyPointsAndCycleTimeRequest.setOverrideFields(jiraBoardSetting.getOverrideFields()); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER_HAS_STORY_POINT().build()); + when(systemUtil.getEnvMap()).thenReturn(Map.of()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getStoryPointSum()).isEqualTo(11); + assertThat(cardCollection.getCardsNumber()).isEqualTo(4); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsAndCycleTime() throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", + boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("\"storyPoints\":0", "\"customfield_10016\":null") + .replaceAll("storyPoints", "customfield_10016"); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getStoryPointSum()).isEqualTo(0); + assertThat(cardCollection.getCardsNumber()).isEqualTo(1); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeWhenBoardTypeIsClassicJira() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() + .build(); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getCardsNumber()).isEqualTo(0); + } + + @Test + void shouldGetCardsWhenCallGetStoryPointsAndCycleTimeWhenDoneTimeGreaterThanSelectedEndTime() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + JiraBoardSetting jiraBoardSetting = CLASSIC_JIRA_BOARD_SETTING_BUILD().build(); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = CLASSIC_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() + .build(); + String allDoneCards = objectMapper.writeValueAsString(NEED_FILTERED_ALL_DONE_CARDS_BUILDER().build()); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "1", 0, 100, token)) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "2", 0, 100, token)) + .thenReturn(CARD_HISTORY_DONE_TIME_GREATER_THAN_END_TIME_BUILDER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getCardsNumber()).isEqualTo(0); + } + + @Test + void shouldReturnBadRequestExceptionWhenBoardTypeIsNotCorrect() { + JiraBoardSetting jiraBoardSetting = INCORRECT_JIRA_BOARD_SETTING_BUILD().build(); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = INCORRECT_JIRA_STORY_POINTS_FORM_ALL_DONE_CARD() + .build(); + List boardColumns = jiraBoardSetting.getBoardColumns(); + List users = List.of("Zhang San"); + + assertThatThrownBy(() -> jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, boardColumns, users, null, CalendarTypeEnum.REGULAR, zoneId)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Board type does not find!"); + } + + @Test + void shouldProcessCustomFieldsForCardsWhenCallGetStoryPointsAndCycleTime() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn( + "{\"total\":1,\"issues\":[{\"expand\":\"expand\",\"id\":\"1\",\"self\":\"https:xxxx/issue/1\",\"key\":\"ADM-455\",\"fields\":{\"customfield_10020\":[{\"id\":16,\"name\":\"Tool Sprint 11\",\"state\":\"closed\",\"boardId\":2,\"goal\":\"goals\",\"startDate\":\"2023-05-15T03:09:23.000Z\",\"endDate\":\"2023-05-28T16:00:00.000Z\",\"completeDate\":\"2023-05-29T03:51:24.898Z\"}],\"customfield_10021\":[{\"self\":\"https:xxxx/10019\",\"value\":\"Impediment\",\"id\":\"10019\"}],\"customfield_10016\":1,\"assignee\":{\"displayName\":\"Zhang San\"}}}]}"); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(FIELD_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(boardUtil.getCycleTimeInfos(any(), any(), any(), any(), any())).thenReturn(CYCLE_TIME_INFO_LIST()); + when(boardUtil.getOriginCycleTimeInfos(any(), any(), any(), any())).thenReturn(CYCLE_TIME_INFO_LIST()); + + CardCollection doneCards = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), "", + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(doneCards.getStoryPointSum()).isEqualTo(1); + assertThat(doneCards.getCardsNumber()).isEqualTo(1); + } + + @Test + void shouldReturnNullWhenCallGetStoryPointsAndCycleTimeAndHistoryIsNull() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn( + "{\"total\":1,\"issues\":[{\"expand\":\"expand\",\"id\":\"1\",\"self\":\"https:xxxx/issue/1\",\"key\":\"ADM-455\",\"fields\":{\"customfield_10020\":[{\"id\":16,\"name\":\"Tool Sprint 11\",\"state\":\"closed\",\"boardId\":2,\"goal\":\"goals\",\"startDate\":\"2023-05-15T03:09:23.000Z\",\"endDate\":\"2023-05-28T16:00:00.000Z\",\"completeDate\":\"2023-05-29T03:51:24.898Z\"}],\"customfield_10021\":[{\"self\":\"https:xxxx/10019\",\"value\":\"Impediment\",\"id\":\"10019\"}],\"customfield_10016\":1,\"assignee\":{\"displayName\":\"Zhang San\"}}}]}"); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(FIELD_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_RESPONSE_BUILDER_TO_DONE().build()); + + CardCollection doneCards = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), null, + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(doneCards.getStoryPointSum()).isEqualTo(0); + assertThat(doneCards.getCardsNumber()).isEqualTo(0); + } + + @Test + void shouldReturnIllegalArgumentExceptionWhenHaveUnknownColumn() throws JsonProcessingException { + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_HAVE_UNKNOWN_COLUMN_BUILD().build(); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD() + .startTime("5") + .build(); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().startTime("5").build(); + String jql = String.format("status in ('%s') AND status changed during (%s, %s)", "DONE", + boardRequestParam.getStartTime(), boardRequestParam.getEndTime()); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build()) + .replaceAll("storyPoints", "customfield_10016"); + List boardColumns = jiraBoardSetting.getBoardColumns(); + List users = List.of("Zhang San"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, QUERY_COUNT, 0, jql, boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(FIELD_RESPONSE_BUILDER().build()); + + assertThatThrownBy(() -> jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards( + storyPointsAndCycleTimeRequest, boardColumns, users, null, CalendarTypeEnum.REGULAR, zoneId)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Type does not find!"); + } + + @Test + void shouldGetRealDoneCardGivenCallGetStoryPointsAndCycleTimeWhenUseHistoricalAssigneeFilter() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = AssigneeFilterMethod.HISTORICAL_ASSIGNEE.getDescription(); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_ASSIGNEE_FILTER_METHOD().build(); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_ASSIGNEE_FILTER_TEST().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD1_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD2_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-520", 0, 100, token)) + .thenReturn(CARD3_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection1 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, + zoneId); + CardCollection cardCollection2 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of("song"), assigneeFilter, CalendarTypeEnum.REGULAR, + zoneId); + + assertThat(cardCollection1.getCardsNumber()).isEqualTo(0); + assertThat(cardCollection2.getCardsNumber()).isEqualTo(1); + assertThat(cardCollection2.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-475"); + } + + @Test + void shouldGetRealDoneCardGivenCallGetStoryPointsAndCycleTimeWhenUseLastAssigneeFilter() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = AssigneeFilterMethod.LAST_ASSIGNEE.getDescription(); + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_ASSIGNEE_FILTER_METHOD().build(); + String allDoneCards = objectMapper + .writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_ASSIGNEE_FILTER_TEST().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD1_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD2_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-520", 0, 100, token)) + .thenReturn(CARD3_HISTORY_FOR_HISTORICAL_ASSIGNEE_FILTER().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection1 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of("yun"), assigneeFilter, CalendarTypeEnum.REGULAR, + zoneId); + CardCollection cardCollection2 = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, + zoneId); + + assertThat(cardCollection1.getCardsNumber()).isEqualTo(1); + assertThat(cardCollection1.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-520"); + assertThat(cardCollection2.getCardsNumber()).isEqualTo(1); + assertThat(cardCollection2.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-475"); + } + + @Test + void shouldGetRealDoneCardsGivenMultipleStatuesMappingToDoneStatusWhenCallGetStoryPointsAndCycleTime() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = "lastAssignee"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES().build(); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, + zoneId); + + assertThat(cardCollection.getCardsNumber()).isEqualTo(1); + assertThat(cardCollection.getJiraCardDTOList().get(0).getBaseInfo().getKey()).isEqualTo("ADM-475"); + } + + @Test + void shouldGetRealDoneCardsGivenHistoryWithNoStatusFieldWhenCallGetStoryPointsAndCycleTime() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = "lastAssignee"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES().build(); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD_HISTORY_WITH_NO_STATUS_FIELD().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of("Da Pei"), assigneeFilter, CalendarTypeEnum.REGULAR, + zoneId); + + assertThat(cardCollection.getCardsNumber()).isZero(); + } + + @Test + void shouldGetRealDoneCardsReworkToInDevTimesGivenNotConsiderFlagIsBlockAndNoExclude() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = "lastAssignee"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() + .treatFlagCardAsBlock(false) + .reworkTimesSetting( + ReworkTimesSetting.builder().reworkState("In Dev").excludedStates(List.of()).build()) + .build(); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD3_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), + List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE, JiraBoardConfigDTOFixture.DISPLAY_NAME_TWO), + assigneeFilter, CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getReworkCardNumber()).isEqualTo(1); + assertThat(cardCollection.getReworkRatio()).isEqualTo(0.5); + assertThat(cardCollection.getJiraCardDTOList().get(0).getTotalReworkTimes()).isEqualTo(3); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) + .isEqualTo(CardStepsEnum.BLOCK); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getTimes()).isEqualTo(1); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getState()) + .isEqualTo(CardStepsEnum.REVIEW); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getTimes()).isEqualTo(1); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(3).getState()) + .isEqualTo(CardStepsEnum.TESTING); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(3).getTimes()).isEqualTo(1); + } + + @Test + void shouldGetRealDoneCardsReworkTimesToInDevGivenConsiderFlagAsBlock() throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = "lastAssignee"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() + .treatFlagCardAsBlock(true) + .reworkTimesSetting( + ReworkTimesSetting.builder().reworkState("In Dev").excludedStates(List.of()).build()) + .build(); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES_WITH_FLAG().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE), + assigneeFilter, CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getReworkCardNumber()).isEqualTo(1); + assertThat(cardCollection.getReworkRatio()).isEqualTo(1); + assertThat(cardCollection.getJiraCardDTOList().get(0).getTotalReworkTimes()).isEqualTo(2); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) + .isEqualTo(CardStepsEnum.BLOCK); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getTimes()).isEqualTo(2); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) + .isEqualTo(CardStepsEnum.BLOCK); + } + + @Test + void shouldGetRealDoneCardsReworkToInDevTimesGivenNotConsiderFlagIsBlockAndExcludeState() + throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = "lastAssignee"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() + .treatFlagCardAsBlock(false) + .reworkTimesSetting( + ReworkTimesSetting.builder().reworkState("In Dev").excludedStates(List.of("Block")).build()) + .build(); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD3_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), + List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE, JiraBoardConfigDTOFixture.DISPLAY_NAME_TWO), + assigneeFilter, CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getReworkCardNumber()).isEqualTo(1); + assertThat(cardCollection.getReworkRatio()).isEqualTo(0.5); + assertThat(cardCollection.getJiraCardDTOList().get(0).getTotalReworkTimes()).isEqualTo(2); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getState()) + .isEqualTo(CardStepsEnum.REVIEW); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(0).getTimes()).isEqualTo(1); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getState()) + .isEqualTo(CardStepsEnum.WAITING_FOR_TESTING); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(1).getTimes()).isZero(); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(2).getState()) + .isEqualTo(CardStepsEnum.TESTING); + assertThat(cardCollection.getJiraCardDTOList().get(0).getReworkTimesInfos().get(2).getTimes()).isEqualTo(1); + } + + @Test + void shouldGetRealDoneCardsReworkTimesToTestingGivenConsiderFlagAsBlock() throws JsonProcessingException { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + String assigneeFilter = "lastAssignee"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); + StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() + .treatFlagCardAsBlock(true) + .reworkTimesSetting( + ReworkTimesSetting.builder().reworkState("Testing").excludedStates(List.of()).build()) + .build(); + String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) + .replaceAll("sprint", "customfield_10020") + .replaceAll("partner", "customfield_10037") + .replaceAll("flagged", "customfield_10021") + .replaceAll("development", "customfield_10000"); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) + .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES_WITH_FLAG().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) + .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); + when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)) + .thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, + jiraBoardSetting.getBoardColumns(), List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE), + assigneeFilter, CalendarTypeEnum.REGULAR, zoneId); + + assertThat(cardCollection.getReworkCardNumber()).isZero(); + assertThat(cardCollection.getReworkRatio()).isZero(); + } + + } + + @Nested + class GetStoryPointsAndCycleTimeForNonDoneCards { + + @Test + void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForActiveSprint() + throws JsonProcessingException { + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn( + objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); + assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); + } + + @Test + void shouldReturnCardsWhenCallGetStoryPointsWhenAssigneeIsNull() throws JsonProcessingException { + String assignName = "Zhang San"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + CardHistoryResponseDTO cardHistoryResponseDTO = CardHistoryResponseDTO.builder() + .isLast(true) + .items(List.of(new HistoryDetail(1, "assignee", Status.builder().name("nonToDisplay").build(), + Status.builder().name("nonFromDisplay").build(), null, null))) + .build(); + AllCardsResponseDTO allCardsResponseDTO = AllCardsResponseDTO.builder() + .total("3") + .issues(List.of( + new JiraCard("1", + JiraCardField.builder() + .assignee(new Assignee(assignName)) + .issuetype(IssueType.builder().name("缺陷").build()) + .storyPoints(2) + .status(new Status(CardStepsEnum.TESTING.getValue())) + .build()), + new JiraCard("2", + JiraCardField.builder() + .issuetype(IssueType.builder().name("缺陷").build()) + .storyPoints(2) + .status(new Status(CardStepsEnum.TESTING.getValue())) + .build()), + new JiraCard("3", + JiraCardField.builder() + .assignee(Assignee.builder().build()) + .issuetype(IssueType.builder().name("缺陷").build()) + .storyPoints(2) + .status(new Status(CardStepsEnum.TESTING.getValue())) + .build()))) + .build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())) + .thenReturn(objectMapper.writeValueAsString(allCardsResponseDTO)); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(cardHistoryResponseDTO); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + + CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(nonDoneCards.getStoryPointSum()).isZero(); + assertThat(nonDoneCards.getCardsNumber()).isEqualTo(1); + } + + @Test + void shouldReturnCardsWhenCallGetStoryPointsWhenHistoryItemIsEmpty() throws JsonProcessingException { + String assignName = "Zhang San"; + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + HashMap issueFieldMap = new HashMap<>(); + FieldResponseDTO targetField = FieldResponseDTO.builder() + .projects(List.of(new Project(List.of(new Issuetype(issueFieldMap))))) + .build(); + CardHistoryResponseDTO cardHistoryResponseDTO = CardHistoryResponseDTO.builder() + .isLast(true) + .items(List.of()) + .build(); + AllCardsResponseDTO allCardsResponseDTO = AllCardsResponseDTO.builder() + .total("3") + .issues(List.of( + new JiraCard("1", + JiraCardField.builder() + .assignee(new Assignee(assignName)) + .issuetype(IssueType.builder().name("缺陷").build()) + .storyPoints(2) + .status(new Status(CardStepsEnum.TESTING.getValue())) + .build()), + new JiraCard("2", + JiraCardField.builder() + .issuetype(IssueType.builder().name("缺陷").build()) + .storyPoints(2) + .status(new Status(CardStepsEnum.TESTING.getValue())) + .build()), + new JiraCard("3", + JiraCardField.builder() + .assignee(Assignee.builder().build()) + .issuetype(IssueType.builder().name("缺陷").build()) + .storyPoints(2) + .status(new Status(CardStepsEnum.TESTING.getValue())) + .build()))) + .build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())) + .thenReturn(objectMapper.writeValueAsString(allCardsResponseDTO)); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(cardHistoryResponseDTO); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(targetField); + + CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(nonDoneCards.getStoryPointSum()).isZero(); + assertThat(nonDoneCards.getCardsNumber()).isEqualTo(1); + } + + @Test + void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForActiveSprintWithStatusIsEmpty() + throws JsonProcessingException { + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD_WITH_EMPTY_STATUS() + .build(); + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn( + objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + + CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); + assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); + } + + @Test + void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForKanban() + throws JsonProcessingException { + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD().build(); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jqlForKanban = "status not in ('" + String.join("','", storyPointsAndCycleTimeRequest.getStatus()) + + "') ORDER BY updated DESC"; + String jqlForActiveSprint = "sprint in openSprints() AND status not in ('" + + String.join("','", storyPointsAndCycleTimeRequest.getStatus()) + "') ORDER BY updated DESC"; + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForActiveSprint, + boardRequestParam.getToken())) + .thenReturn(""); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForKanban, + boardRequestParam.getToken())) + .thenReturn( + objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + + CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); + assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); + } + + @Test + void shouldReturnCardsWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForKanbanWithStatusIsEmpty() + throws JsonProcessingException { + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD_WITH_EMPTY_STATUS() + .build(); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jqlForKanban = "ORDER BY updated DESC"; + String jqlForActiveSprint = "sprint in openSprints() ORDER BY updated DESC"; + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForActiveSprint, + boardRequestParam.getToken())) + .thenReturn(""); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForKanban, + boardRequestParam.getToken())) + .thenReturn( + objectMapper.writeValueAsString(ALL_NON_DONE_CARDS_RESPONSE_FOR_STORY_POINT_BUILDER().build())); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + + CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); + assertThat(nonDoneCards.getCardsNumber()).isEqualTo(3); + } + + @Test + void shouldReturnCardsWithSprintWhenCallGetStoryPointsAndCycleTimeForNonDoneCardsForKanbanWithStatusIsEmpty() { + JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_BUILD().build(); + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + StoryPointsAndCycleTimeRequest storyPointsAndCycleTimeRequest = STORY_POINTS_FORM_ALL_DONE_CARD_WITH_EMPTY_STATUS() + .build(); + BoardRequestParam boardRequestParam = BOARD_REQUEST_BUILDER().build(); + String jqlForActiveSprint = "sprint in openSprints() ORDER BY updated DESC"; + String allDoneCards = JiraBoardConfigDTOFixture.JIRA_CARD_WITH_TWO_SPRINT; + when(urlGenerator.getUri(any())).thenReturn(baseUrl); + when(jiraFeignClient.getJiraCards(baseUrl, BOARD_ID, NONE_DONE_MAX_QUERY_COUNT, 0, jqlForActiveSprint, + boardRequestParam.getToken())) + .thenReturn(allDoneCards); + when(jiraFeignClient.getTargetField(any(), any(), any())).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); + when(jiraFeignClient.getJiraCardHistoryByCount(any(), any(), anyInt(), anyInt(), any())) + .thenReturn(CARD_HISTORY_MULTI_RESPONSE_BUILDER().build()); + + CardCollection nonDoneCards = jiraService.getStoryPointsAndCycleTimeForNonDoneCards( + storyPointsAndCycleTimeRequest, jiraBoardSetting.getBoardColumns(), List.of("Zhang San"), + CalendarTypeEnum.REGULAR, zoneId); + + assertThat(nonDoneCards.getStoryPointSum()).isEqualTo(0); + assertThat(nonDoneCards.getCardsNumber()).isEqualTo(1); + assertThat(nonDoneCards.getJiraCardDTOList().get(0).getBaseInfo().getFields().getSprint().getName()) + .isEqualTo("TS Sprint 1"); + } + + } + + @Nested + class GetJiraBoardConfig { + + @Test + void shouldReturnJiraBoardConfigDTOWhenCallGetJiraBoardConfig() { + URI baseUrl = URI.create(SITE_ATLASSIAN_NET); + JiraBoardConfigDTO mockResponse = JIRA_BOARD_CONFIG_RESPONSE_BUILDER().build(); + + when(jiraFeignClient.getJiraBoardConfiguration(any(), any(), any())).thenReturn(mockResponse); + JiraBoardConfigDTO result = jiraService.getJiraBoardConfig(baseUrl, BOARD_ID, token); + + assertThat(mockResponse).isEqualTo(result); + } - @Test - void shouldGetRealDoneCardsReworkTimesToTestingGivenConsiderFlagAsBlock() throws JsonProcessingException { - - URI baseUrl = URI.create(SITE_ATLASSIAN_NET); - String token = "token"; - String assigneeFilter = "lastAssignee"; - - // request param - JiraBoardSetting jiraBoardSetting = JIRA_BOARD_SETTING_WITH_HISTORICAL_ASSIGNEE_FILTER_METHOD().build(); - StoryPointsAndCycleTimeRequest request = STORY_POINTS_REQUEST_WITH_MULTIPLE_REAL_DONE_STATUSES() - .treatFlagCardAsBlock(true) - .reworkTimesSetting(ReworkTimesSetting.builder().reworkState("Testing").excludedStates(List.of()).build()) - .build(); - - // return value - String allDoneCards = objectMapper.writeValueAsString(ALL_DONE_CARDS_RESPONSE_FOR_MULTIPLE_STATUS().build()) - .replaceAll("sprint", "customfield_10020") - .replaceAll("partner", "customfield_10037") - .replaceAll("flagged", "customfield_10021") - .replaceAll("development", "customfield_10000"); - - when(urlGenerator.getUri(any())).thenReturn(baseUrl); - when(jiraFeignClient.getJiraCards(any(), any(), anyInt(), anyInt(), any(), any())).thenReturn(allDoneCards); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-475", 0, 100, token)) - .thenReturn(CARD1_HISTORY_FOR_MULTIPLE_STATUSES_WITH_FLAG().build()); - when(jiraFeignClient.getJiraCardHistoryByCount(baseUrl, "ADM-524", 0, 100, token)) - .thenReturn(CARD2_HISTORY_FOR_MULTIPLE_STATUSES().build()); - when(jiraFeignClient.getTargetField(baseUrl, "PLL", token)).thenReturn(ALL_FIELD_RESPONSE_BUILDER().build()); - - CardCollection cardCollection = jiraService.getStoryPointsAndCycleTimeAndReworkInfoForDoneCards(request, - jiraBoardSetting.getBoardColumns(), List.of(JiraBoardConfigDTOFixture.DISPLAY_NAME_ONE), assigneeFilter, - CalendarTypeEnum.REGULAR, ZoneId.of("Asia/Shanghai")); - - assertThat(cardCollection.getReworkCardNumber()).isZero(); - assertThat(cardCollection.getReworkRatio()).isZero(); } } diff --git a/backend/src/test/java/heartbeat/service/report/BoardCsvFixture.java b/backend/src/test/java/heartbeat/service/report/BoardCsvFixture.java index b360cf8433..4c5552cf5a 100644 --- a/backend/src/test/java/heartbeat/service/report/BoardCsvFixture.java +++ b/backend/src/test/java/heartbeat/service/report/BoardCsvFixture.java @@ -262,7 +262,7 @@ public static JiraCardField MOCK_JIRA_CARD() { public static List MOCK_REWORK_TIMES_INFO_LIST() { return List.of(ReworkTimesInfo.builder().state(CardStepsEnum.BLOCK).times(2).build(), ReworkTimesInfo.builder().state(CardStepsEnum.REVIEW).times(0).build(), - ReworkTimesInfo.builder().state(CardStepsEnum.WAITING).times(1).build(), + ReworkTimesInfo.builder().state(CardStepsEnum.WAITING_FOR_TESTING).times(1).build(), ReworkTimesInfo.builder().state(CardStepsEnum.TESTING).times(0).build(), ReworkTimesInfo.builder().state(CardStepsEnum.DONE).times(0).build()); } diff --git a/backend/src/test/java/heartbeat/service/report/ReworkFixture.java b/backend/src/test/java/heartbeat/service/report/ReworkFixture.java index 0b3f2de3bf..48b1584baf 100644 --- a/backend/src/test/java/heartbeat/service/report/ReworkFixture.java +++ b/backend/src/test/java/heartbeat/service/report/ReworkFixture.java @@ -8,20 +8,25 @@ import static heartbeat.controller.board.dto.request.CardStepsEnum.ANALYSE; import static heartbeat.controller.board.dto.request.CardStepsEnum.BLOCK; +import static heartbeat.controller.board.dto.request.CardStepsEnum.DESIGN; import static heartbeat.controller.board.dto.request.CardStepsEnum.DEVELOPMENT; import static heartbeat.controller.board.dto.request.CardStepsEnum.DONE; import static heartbeat.controller.board.dto.request.CardStepsEnum.REVIEW; import static heartbeat.controller.board.dto.request.CardStepsEnum.TESTING; import static heartbeat.controller.board.dto.request.CardStepsEnum.TODO; -import static heartbeat.controller.board.dto.request.CardStepsEnum.WAITING; +import static heartbeat.controller.board.dto.request.CardStepsEnum.WAITING_FOR_DEPLOYMENT; +import static heartbeat.controller.board.dto.request.CardStepsEnum.WAITING_FOR_TESTING; public class ReworkFixture { public static CardCollection MOCK_CARD_COLLECTION() { - List reworkTimesInfos = List.of(ReworkTimesInfo.builder().state(ANALYSE).times(1).build(), + List reworkTimesInfos = List.of( + ReworkTimesInfo.builder().state(WAITING_FOR_DEPLOYMENT).times(1).build(), + ReworkTimesInfo.builder().state(ANALYSE).times(1).build(), + ReworkTimesInfo.builder().state(DESIGN).times(1).build(), ReworkTimesInfo.builder().state(DEVELOPMENT).times(1).build(), ReworkTimesInfo.builder().state(BLOCK).times(1).build(), - ReworkTimesInfo.builder().state(WAITING).times(1).build(), + ReworkTimesInfo.builder().state(WAITING_FOR_TESTING).times(1).build(), ReworkTimesInfo.builder().state(REVIEW).times(1).build(), ReworkTimesInfo.builder().state(TESTING).times(1).build(), ReworkTimesInfo.builder().state(DONE).times(1).build()); @@ -39,7 +44,7 @@ public static CardCollection MOCK_CARD_COLLECTION_WITH_TODO() { List reworkTimesInfos = List.of(ReworkTimesInfo.builder().state(TODO).times(1).build(), ReworkTimesInfo.builder().state(DEVELOPMENT).times(1).build(), ReworkTimesInfo.builder().state(BLOCK).times(1).build(), - ReworkTimesInfo.builder().state(WAITING).times(1).build(), + ReworkTimesInfo.builder().state(WAITING_FOR_TESTING).times(1).build(), ReworkTimesInfo.builder().state(REVIEW).times(1).build(), ReworkTimesInfo.builder().state(DONE).times(1).build()); List jiraCardList = List.of(JiraCardDTO.builder().reworkTimesInfos(reworkTimesInfos).build(), diff --git a/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx b/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx index 9a3593954e..0999aea40b 100644 --- a/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx +++ b/frontend/__tests__/containers/MetricsStep/CycleTime.test.tsx @@ -234,7 +234,7 @@ describe('CycleTime', () => { const listBox = within(screen.getByRole('listbox')); await act(async () => { - await userEvent.click(listBox.getAllByRole('option')[8]); + await userEvent.click(listBox.getAllByRole('option')[10]); }); const inputElements = screen.getAllByRole('combobox'); @@ -254,7 +254,7 @@ describe('CycleTime', () => { const listBox = within(screen.getByRole('listbox')); await act(async () => { - await userEvent.click(listBox.getAllByRole('option')[8]); + await userEvent.click(listBox.getAllByRole('option')[10]); }); await act(async () => { @@ -263,7 +263,7 @@ describe('CycleTime', () => { const newListBox = within(screen.getByRole('listbox')); await act(async () => { - await userEvent.click(newListBox.getAllByRole('option')[7]); + await userEvent.click(newListBox.getAllByRole('option')[8]); }); const inputElements = screen.getAllByRole('combobox'); @@ -383,7 +383,7 @@ describe('CycleTime', () => { const columnsArray = screen.getAllByRole('button', { name: LIST_OPEN }); await userEvent.click(columnsArray[0]); const listBox = within(screen.getByRole('listbox')); - await userEvent.click(listBox.getAllByRole('option')[8]); + await userEvent.click(listBox.getAllByRole('option')[10]); const inputElements = screen.getAllByRole('combobox'); const selectedInputValue = inputElements.map((option) => option.getAttribute('value'))[0]; @@ -396,10 +396,10 @@ describe('CycleTime', () => { const columnsArray = screen.getAllByRole('button', { name: LIST_OPEN }); await userEvent.click(columnsArray[0]); const listBox = within(screen.getByRole('listbox')); - await userEvent.click(listBox.getAllByRole('option')[8]); + await userEvent.click(listBox.getAllByRole('option')[10]); await userEvent.click(columnsArray[0]); const newListBox = within(screen.getByRole('listbox')); - await userEvent.click(newListBox.getAllByRole('option')[7]); + await userEvent.click(newListBox.getAllByRole('option')[8]); const inputElements = screen.getAllByRole('combobox'); const selectedInputValue = inputElements.map((option) => option.getAttribute('value'))[0]; diff --git a/frontend/__tests__/fixtures.ts b/frontend/__tests__/fixtures.ts index d69c362ebe..dfabcfaed6 100644 --- a/frontend/__tests__/fixtures.ts +++ b/frontend/__tests__/fixtures.ts @@ -502,10 +502,12 @@ export const MOCK_REPORT_RESPONSE_WITH_AVERAGE_EXCEPTION: ReportResponseDTO = { reworkState: 'In Dev', fromAnalysis: null, fromInDev: null, + fromDesign: 111, fromBlock: 111, fromReview: 111, fromWaitingForTesting: 111, fromTesting: null, + fromWaitingForDeployment: null, fromDone: 111, totalReworkCards: 111, reworkCardsRatio: 0.8888, @@ -639,11 +641,13 @@ export const MOCK_REPORT_RESPONSE: ReportResponseDTO = { totalReworkTimes: 111, reworkState: 'In Dev', fromAnalysis: null, + fromDesign: 111, fromInDev: null, fromBlock: 111, fromReview: 111, fromWaitingForTesting: 111, fromTesting: null, + fromWaitingForDeployment: null, fromDone: 111, totalReworkCards: 111, reworkCardsRatio: 0.8888, @@ -767,11 +771,13 @@ export const MOCK_REPORT_MOCK_PIPELINE_RESPONSE: ReportResponseDTO = { totalReworkTimes: 111, reworkState: 'In Dev', fromAnalysis: null, + fromDesign: 111, fromInDev: null, fromBlock: 111, fromReview: 111, fromWaitingForTesting: 111, fromTesting: null, + fromWaitingForDeployment: null, fromDone: 111, totalReworkCards: 111, reworkCardsRatio: 0.8888, diff --git a/frontend/__tests__/hooks/reportMapper/report.test.tsx b/frontend/__tests__/hooks/reportMapper/report.test.tsx index bda64b3d40..0e8b5da059 100644 --- a/frontend/__tests__/hooks/reportMapper/report.test.tsx +++ b/frontend/__tests__/hooks/reportMapper/report.test.tsx @@ -68,10 +68,12 @@ export const EXPECTED_REPORT_VALUES = { reworkState: 'In Dev', fromAnalysis: null, fromInDev: null, + fromDesign: 111, fromBlock: 111, fromReview: 111, fromWaitingForTesting: 111, fromTesting: null, + fromWaitingForDeployment: null, fromDone: 111, totalReworkCards: 111, reworkCardsRatio: 0.8888, @@ -201,10 +203,10 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 3, + id: 2, name: ( - From block to in dev + From design to in dev ), valueList: [ @@ -218,7 +220,7 @@ export const EXPECTED_REPORT_VALUES = { id: 4, name: ( - From review to in dev + From block to in dev ), valueList: [ @@ -230,6 +232,20 @@ export const EXPECTED_REPORT_VALUES = { }, { id: 5, + name: ( + + From review to in dev + + ), + valueList: [ + { + value: 111, + unit: ' (times)', + }, + ], + }, + { + id: 6, name: ( From waiting for testing to in dev @@ -243,7 +259,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 7, + id: 9, name: ( From done to in dev @@ -257,7 +273,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 8, + id: 10, name: Total rework cards, valueList: [ { @@ -267,7 +283,7 @@ export const EXPECTED_REPORT_VALUES = { ], }, { - id: 9, + id: 11, name: Rework cards ratio, valueList: [ { diff --git a/frontend/__tests__/utils/Util.test.tsx b/frontend/__tests__/utils/Util.test.tsx index af16258f7e..ab2eaf961b 100644 --- a/frontend/__tests__/utils/Util.test.tsx +++ b/frontend/__tests__/utils/Util.test.tsx @@ -293,7 +293,7 @@ describe('getSortedAndDeduplicationBoardingMapping function', () => { METRICS_CONSTANTS.blockValue, METRICS_CONSTANTS.inDevValue, METRICS_CONSTANTS.reviewValue, - METRICS_CONSTANTS.waitingValue, + METRICS_CONSTANTS.waitingForTestingValue, METRICS_CONSTANTS.reviewValue, ].map((value) => ({ value: value, @@ -307,7 +307,7 @@ describe('getSortedAndDeduplicationBoardingMapping function', () => { METRICS_CONSTANTS.inDevValue, METRICS_CONSTANTS.blockValue, METRICS_CONSTANTS.reviewValue, - METRICS_CONSTANTS.waitingValue, + METRICS_CONSTANTS.waitingForTestingValue, METRICS_CONSTANTS.testingValue, METRICS_CONSTANTS.doneValue, ]; diff --git a/frontend/e2e/fixtures/create-new/metrics-step.ts b/frontend/e2e/fixtures/create-new/metrics-step.ts index 790142bc83..ed2bd5a85c 100644 --- a/frontend/e2e/fixtures/create-new/metrics-step.ts +++ b/frontend/e2e/fixtures/create-new/metrics-step.ts @@ -225,3 +225,34 @@ export const configWithoutBlockColumn = { }, reworkTimesSettings: { excludeStates: [], reworkState: 'In Dev' }, }; + +export const configWithDesignAndWaitingForDevelopmentStatus = { + ...config, + cycleTime: { + type: 'byColumn', + jiraColumns: [ + { + TODO: 'Design', + }, + { + Doing: 'In Dev', + }, + { + Blocked: 'Block', + }, + { + Review: 'Review', + }, + { + 'READY FOR TESTING': 'Waiting for deployment', + }, + { + Testing: 'Testing', + }, + { + Done: 'Done', + }, + ], + treatFlagCardAsBlock: false, + }, +}; diff --git a/frontend/e2e/fixtures/create-new/report-result.ts b/frontend/e2e/fixtures/create-new/report-result.ts index 37cddc80b5..34ed21b308 100644 --- a/frontend/e2e/fixtures/create-new/report-result.ts +++ b/frontend/e2e/fixtures/create-new/report-result.ts @@ -79,6 +79,39 @@ export const BOARD_METRICS_RESULT_MULTIPLE_RANGES: IBoardMetricsResult[] = [ }, ]; +export const BOARD_METRICS_WITH_DESIGN_AND_WAITING_FOR_DEPLOYMENT_RESULT_MULTIPLE_RANGES: IBoardMetricsResult[] = [ + { + velocity: '1', + throughput: '1', + averageCycleTimeForSP: '0.99', + averageCycleTimeForCard: '0.99', + totalReworkTimes: '0', + totalReworkCards: '0', + reworkCardsRatio: '0.0000', + reworkThroughput: '1', + }, + { + velocity: '1', + throughput: '1', + averageCycleTimeForSP: '6.87', + averageCycleTimeForCard: '6.87', + totalReworkTimes: '1', + totalReworkCards: '1', + reworkCardsRatio: '1.0000', + reworkThroughput: '1', + }, + { + velocity: '5.5', + throughput: '3', + averageCycleTimeForSP: '11.35', + averageCycleTimeForCard: '20.81', + totalReworkTimes: '1', + totalReworkCards: '1', + reworkCardsRatio: '0.3333', + reworkThroughput: '3', + }, +]; + export const BOARD_METRICS_VELOCITY_MULTIPLE_RANGES: IBoardMetricsDetailItem[][] = [ [ { @@ -112,7 +145,7 @@ export const BOARD_METRICS_VELOCITY_MULTIPLE_RANGES: IBoardMetricsDetailItem[][] ], ]; -export const BOARD_METRICS_CYCLETIME_MULTIPLE_RANGES: IBoardCycletimeDetailItem[][] = [ +export const BOARD_METRICS_CYCLE_TIME_MULTIPLE_RANGES: IBoardCycletimeDetailItem[][] = [ [ { name: 'Average cycle time', @@ -245,6 +278,164 @@ export const BOARD_METRICS_CYCLETIME_MULTIPLE_RANGES: IBoardCycletimeDetailItem[ ], ]; +export const BOARD_METRICS_WITH_DESIGN_AND_WAITING_FOR_DEPLOYMENT_CYCLE_TIME: IBoardCycletimeDetailItem[][] = [ + [ + { + name: 'Average cycle time', + lines: ['0.99(Days/SP)', '0.99(Days/Card)'], + }, + { + name: 'Total design time / Total cycle time', + lines: ['1.01%'], + }, + { + name: 'Total development time / Total cycle time', + lines: ['14.14%'], + }, + { + name: 'Total review time / Total cycle time', + lines: ['0%'], + }, + { + name: 'Total testing time / Total cycle time', + lines: ['0%'], + }, + { + name: 'Total waiting for deployment time / Total cycle time', + lines: ['84.85%'], + }, + { + name: 'Average design time', + lines: ['0.01(Days/SP)', '0.01(Days/Card)'], + }, + { + name: 'Average development time', + lines: ['0.14(Days/SP)', '0.14(Days/Card)'], + }, + + { + name: 'Average review time', + lines: ['0.00(Days/SP)', '0.00(Days/Card)'], + }, + { + name: 'Average testing time', + lines: ['0.00(Days/SP)', '0.00(Days/Card)'], + }, + { + name: 'Average waiting for deployment time', + lines: ['0.84(Days/SP)', '0.84(Days/Card)'], + }, + ], + [ + { + name: 'Average cycle time', + lines: ['6.87(Days/SP)', '6.87(Days/Card)'], + }, + { + name: 'Total design time / Total cycle time', + lines: ['55.9%'], + }, + { + name: 'Total development time / Total cycle time', + lines: ['29.11%'], + }, + { + name: 'Total block time / Total cycle time', + lines: ['2.18%'], + }, + { + name: 'Total review time / Total cycle time', + lines: ['0%'], + }, + { + name: 'Total testing time / Total cycle time', + lines: ['10.77%'], + }, + { + name: 'Total waiting for deployment time / Total cycle time', + lines: ['2.04%'], + }, + { + name: 'Average design time', + lines: ['3.84(Days/SP)', '3.84(Days/Card)'], + }, + { + name: 'Average development time', + lines: ['2.00(Days/SP)', '2.00(Days/Card)'], + }, + { + name: 'Average block time', + lines: ['0.15(Days/SP)', '0.15(Days/Card)'], + }, + { + name: 'Average review time', + lines: ['0.00(Days/SP)', '0.00(Days/Card)'], + }, + { + name: 'Average testing time', + lines: ['0.74(Days/SP)', '0.74(Days/Card)'], + }, + { + name: 'Average waiting for deployment time', + lines: ['0.14(Days/SP)', '0.14(Days/Card)'], + }, + ], + [ + { + name: 'Average cycle time', + lines: ['11.35(Days/SP)', '20.81(Days/Card)'], + }, + { + name: 'Total design time / Total cycle time', + lines: ['52.52%'], + }, + { + name: 'Total development time / Total cycle time', + lines: ['35.27%'], + }, + { + name: 'Total block time / Total cycle time', + lines: ['3.19%'], + }, + { + name: 'Total review time / Total cycle time', + lines: ['5.86%'], + }, + { + name: 'Total testing time / Total cycle time', + lines: ['1.57%'], + }, + { + name: 'Total waiting for deployment time / Total cycle time', + lines: ['1.59%'], + }, + { + name: 'Average design time', + lines: ['5.96(Days/SP)', '10.93(Days/Card)'], + }, + { + name: 'Average development time', + lines: ['4.00(Days/SP)', '7.34(Days/Card)'], + }, + { + name: 'Average block time', + lines: ['0.36(Days/SP)', '0.66(Days/Card)'], + }, + { + name: 'Average review time', + lines: ['0.67(Days/SP)', '1.22(Days/Card)'], + }, + { + name: 'Average testing time', + lines: ['0.18(Days/SP)', '0.33(Days/Card)'], + }, + { + name: 'Average waiting for deployment time', + lines: ['0.18(Days/SP)', '0.33(Days/Card)'], + }, + ], +]; + export const BOARD_METRICS_CLASSIFICATION_MULTIPLE_RANGES: IBoardClassificationDetailItem[][] = [ [ { diff --git a/frontend/e2e/pages/metrics/report-step.ts b/frontend/e2e/pages/metrics/report-step.ts index e353f9a9f7..92a0278e57 100644 --- a/frontend/e2e/pages/metrics/report-step.ts +++ b/frontend/e2e/pages/metrics/report-step.ts @@ -581,10 +581,12 @@ export class ReportStep { trigger, rangeCount, csvCompareLines, + fileNamePrefix, }: { trigger: Locator; rangeCount: number; csvCompareLines?: ICsvComparedLines; + fileNamePrefix?: string; }) { const isNeedToCompareCsvLines = csvCompareLines !== undefined; const isRangesCountAndCsvCountEqual = isNeedToCompareCsvLines && rangeCount !== csvCompareLines.length; @@ -621,7 +623,13 @@ export class ReportStep { await download.saveAs(savePath); const downloadPath = await download.path(); const fileDataString = fs.readFileSync(downloadPath, 'utf8'); - const localCsvFile = fs.readFileSync(path.resolve(__dirname, '../../fixtures/create-new', `./${fileName}.csv`)); + const localCsvFile = fs.readFileSync( + path.resolve( + __dirname, + '../../fixtures/create-new', + `./${fileNamePrefix ? fileNamePrefix + fileName : fileName}.csv`, + ), + ); const localCsv = parse(localCsvFile, { to: isNeedToCompareCsvLines ? csvCompareLines[fileName] : undefined }); const downloadCsv = parse(fileDataString, { to: isNeedToCompareCsvLines ? csvCompareLines[fileName] : undefined, @@ -692,8 +700,12 @@ export class ReportStep { }); } - async checkMetricDownloadDataForMultipleRanges(rangeCount: number) { - await this.downloadFileAndCheckForMultipleRanges({ trigger: this.exportMetricData, rangeCount }); + async checkMetricDownloadDataForMultipleRanges(rangeCount: number, fileNamePrefix?: string) { + await this.downloadFileAndCheckForMultipleRanges({ + trigger: this.exportMetricData, + rangeCount, + fileNamePrefix, + }); } async checkMetricDownloadDataByStatus() { diff --git a/frontend/e2e/specs/major-path/create-a-new-project.spec.ts b/frontend/e2e/specs/major-path/create-a-new-project.spec.ts index e91dc2e884..ee6681e59f 100644 --- a/frontend/e2e/specs/major-path/create-a-new-project.spec.ts +++ b/frontend/e2e/specs/major-path/create-a-new-project.spec.ts @@ -1,12 +1,17 @@ import { BOARD_METRICS_RESULT_MULTIPLE_RANGES, BOARD_METRICS_VELOCITY_MULTIPLE_RANGES, - BOARD_METRICS_CYCLETIME_MULTIPLE_RANGES, + BOARD_METRICS_CYCLE_TIME_MULTIPLE_RANGES, BOARD_METRICS_CLASSIFICATION_MULTIPLE_RANGES, BOARD_METRICS_REWORK_MULTIPLE_RANGES, DORA_METRICS_RESULT_MULTIPLE_RANGES, + BOARD_METRICS_WITH_DESIGN_AND_WAITING_FOR_DEPLOYMENT_RESULT_MULTIPLE_RANGES, + BOARD_METRICS_WITH_DESIGN_AND_WAITING_FOR_DEPLOYMENT_CYCLE_TIME, } from '../../fixtures/create-new/report-result'; -import { configWithoutBlockColumn as metricsStepWithoutBlockColumnData } from '../../fixtures/create-new/metrics-step'; +import { + configWithDesignAndWaitingForDevelopmentStatus, + configWithoutBlockColumn as metricsStepWithoutBlockColumnData, +} from '../../fixtures/create-new/metrics-step'; import { configWithoutBlockColumn as configWithoutBlockColumnData } from '../../fixtures/create-new/config-step'; import { cycleTimeByStatusFixture } from '../../fixtures/cycle-time-by-status/cycle-time-by-status-fixture'; import { BAORD_CSV_COMPARED_LINES } from '../../fixtures/create-new/report-result'; @@ -83,7 +88,7 @@ test('Create a new project', async ({ homePage, configStep, metricsStep, reportS await reportStep.checkBoardMetricsDetailsForMultipleRanges({ projectCreationType: ProjectCreationType.CREATE_A_NEW_PROJECT, velocityData: BOARD_METRICS_VELOCITY_MULTIPLE_RANGES, - cycleTimeData: BOARD_METRICS_CYCLETIME_MULTIPLE_RANGES, + cycleTimeData: BOARD_METRICS_CYCLE_TIME_MULTIPLE_RANGES, classificationData: BOARD_METRICS_CLASSIFICATION_MULTIPLE_RANGES, reworkData: BOARD_METRICS_REWORK_MULTIPLE_RANGES, csvCompareLines: BAORD_CSV_COMPARED_LINES, @@ -135,3 +140,69 @@ test('Create a new project without block column in boarding mapping', async ({ await reportStep.checkProjectName(configStepData.projectName); await reportStep.checkBoardDownloadDataWithoutBlockForMultipleRanges(3); }); + +test('Create a new project with design and waiting for deployment in the cycle time status', async ({ + homePage, + configStep, + metricsStep, + reportStep, +}) => { + const hbStateData = configWithDesignAndWaitingForDevelopmentStatus.cycleTime.jiraColumns.map( + (jiraToHBSingleMap) => Object.values(jiraToHBSingleMap)[0], + ); + + await homePage.goto(); + await homePage.createANewProject(); + await configStep.waitForShown(); + await configStep.typeInProjectName(configStepData.projectName); + await configStep.selectRegularCalendar(configStepData.calendarType); + await configStep.typeInMultipleRanges(configStepData.dateRange); + await configStep.selectAllRequiredMetrics(); + await configStep.checkBoardFormVisible(); + await configStep.checkPipelineToolFormVisible(); + await configStep.checkSourceControlFormVisible(); + await configStep.fillAndVerifyBoardConfig(configStepData.board); + await configStep.fillAndVerifyPipelineToolForm(configStepData.pipelineTool); + await configStep.fillAndVerifySourceControlForm(configStepData.sourceControl); + await configStep.validateNextButtonClickable(); + await configStep.goToMetrics(); + + await metricsStep.checkBoardConfigurationVisible(); + await metricsStep.checkPipelineConfigurationVisible(); + await metricsStep.checkLastAssigneeCrewFilterChecked(); + await metricsStep.checkCycleTimeSettingIsByColumn(); + await metricsStep.waitForHiddenLoading(); + await metricsStep.selectCrews(configWithDesignAndWaitingForDevelopmentStatus.crews); + await metricsStep.selectCycleTimeSettingsType(configWithDesignAndWaitingForDevelopmentStatus.cycleTime.type); + await metricsStep.selectHeartbeatState(hbStateData, true); + await metricsStep.checkHeartbeatStateIsSet(hbStateData, true); + await metricsStep.selectClassifications(configWithDesignAndWaitingForDevelopmentStatus.classification); + await metricsStep.selectClassificationCharts(configWithDesignAndWaitingForDevelopmentStatus.classificationCharts); + await metricsStep.selectDefaultGivenPipelineSetting(configWithDesignAndWaitingForDevelopmentStatus.deployment); + await metricsStep.selectAllPipelineCrews(); + await metricsStep.selectReworkSettings(configWithDesignAndWaitingForDevelopmentStatus.reworkTimesSettings); + await metricsStep.saveConfigStepAsJSONThenVerifyDownloadFile(configWithDesignAndWaitingForDevelopmentStatus); + await metricsStep.goToReportPage(); + + await reportStep.confirmGeneratedReport(); + await reportStep.checkProjectName(configWithDesignAndWaitingForDevelopmentStatus.projectName); + await reportStep.goToReportListTab(); + await reportStep.checkExplanation(); + await reportStep.checkBoardMetricsForMultipleRanges( + BOARD_METRICS_WITH_DESIGN_AND_WAITING_FOR_DEPLOYMENT_RESULT_MULTIPLE_RANGES, + ); + await reportStep.checkBoardMetricsDetailsForMultipleRanges({ + projectCreationType: ProjectCreationType.CREATE_A_NEW_PROJECT, + velocityData: BOARD_METRICS_VELOCITY_MULTIPLE_RANGES, + cycleTimeData: BOARD_METRICS_WITH_DESIGN_AND_WAITING_FOR_DEPLOYMENT_CYCLE_TIME, + classificationData: BOARD_METRICS_CLASSIFICATION_MULTIPLE_RANGES, + reworkData: BOARD_METRICS_REWORK_MULTIPLE_RANGES, + csvCompareLines: BAORD_CSV_COMPARED_LINES, + }); + await reportStep.checkDoraMetricsForMultipleRanges(DORA_METRICS_RESULT_MULTIPLE_RANGES); + await reportStep.checkDoraMetricsDetailsForMultipleRanges({ + doraMetricsReportData: DORA_METRICS_RESULT_MULTIPLE_RANGES, + projectCreationType: ProjectCreationType.CREATE_A_NEW_PROJECT, + }); + // await reportStep.checkMetricDownloadDataForMultipleRanges(3, 'with-design-and-wait-for-deployment-'); +}); diff --git a/frontend/e2e/specs/major-path/import-project-from-file.spec.ts b/frontend/e2e/specs/major-path/import-project-from-file.spec.ts index 5be485a0e4..4323c98fb4 100644 --- a/frontend/e2e/specs/major-path/import-project-from-file.spec.ts +++ b/frontend/e2e/specs/major-path/import-project-from-file.spec.ts @@ -4,7 +4,7 @@ import { FLAG_AS_BLOCK_PROJECT_BOARD_METRICS_RESULT, BOARD_METRICS_RESULT_MULTIPLE_RANGES, BOARD_METRICS_VELOCITY_MULTIPLE_RANGES, - BOARD_METRICS_CYCLETIME_MULTIPLE_RANGES, + BOARD_METRICS_CYCLE_TIME_MULTIPLE_RANGES, BOARD_METRICS_CLASSIFICATION_MULTIPLE_RANGES, BOARD_METRICS_REWORK_MULTIPLE_RANGES, BAORD_CSV_COMPARED_LINES, @@ -73,7 +73,7 @@ test('Import project from file with all ranges API succeed', async ({ await reportStep.checkBoardMetricsDetailsForMultipleRanges({ projectCreationType: ProjectCreationType.CREATE_A_NEW_PROJECT, velocityData: BOARD_METRICS_VELOCITY_MULTIPLE_RANGES, - cycleTimeData: BOARD_METRICS_CYCLETIME_MULTIPLE_RANGES, + cycleTimeData: BOARD_METRICS_CYCLE_TIME_MULTIPLE_RANGES, classificationData: BOARD_METRICS_CLASSIFICATION_MULTIPLE_RANGES, reworkData: BOARD_METRICS_REWORK_MULTIPLE_RANGES, csvCompareLines: BAORD_CSV_COMPARED_LINES, diff --git a/frontend/src/clients/report/ReportClient.ts b/frontend/src/clients/report/ReportClient.ts index a57dad9369..481c76200c 100644 --- a/frontend/src/clients/report/ReportClient.ts +++ b/frontend/src/clients/report/ReportClient.ts @@ -38,11 +38,13 @@ export class ReportClient extends HttpClient { totalReworkTimes: 0, reworkState: 'Done', fromAnalysis: 0, + fromDesign: 0, fromInDev: 0, fromBlock: 0, fromWaitingForTesting: 0, fromTesting: 0, fromReview: 0, + fromWaitingForDeployment: 0, fromDone: 0, totalReworkCards: 0, throughput: 1, diff --git a/frontend/src/clients/report/dto/response.ts b/frontend/src/clients/report/dto/response.ts index 06e91c8e26..c14254e14f 100644 --- a/frontend/src/clients/report/dto/response.ts +++ b/frontend/src/clients/report/dto/response.ts @@ -47,10 +47,12 @@ export interface ReworkTimeResponse { totalReworkTimes: number; reworkState: string; fromAnalysis: number | null; + fromDesign: number | null; fromInDev: number | null; fromBlock: number | null; fromWaitingForTesting: number | null; fromTesting: number | null; + fromWaitingForDeployment: number | null; fromReview: number | null; fromDone: number | null; totalReworkCards: number; diff --git a/frontend/src/constants/resources.ts b/frontend/src/constants/resources.ts index dc3e793fb7..e3d2c388b5 100644 --- a/frontend/src/constants/resources.ts +++ b/frontend/src/constants/resources.ts @@ -222,20 +222,24 @@ export const METRICS_CONSTANTS = { doneKeyFromBackend: 'done', todoValue: 'To do', analysisValue: 'Analysis', + designValue: 'Design', inDevValue: 'In Dev', blockValue: 'Block', - waitingValue: 'Waiting for testing', + waitingForTestingValue: 'Waiting for testing', testingValue: 'Testing', reviewValue: 'Review', + waitingForDeploymentValue: 'Waiting for deployment', }; export const CYCLE_TIME_CHARTS_MAPPING: Record = { - [METRICS_CONSTANTS.waitingValue]: 'Waiting for testing time', [METRICS_CONSTANTS.inDevValue]: 'Development time', + [METRICS_CONSTANTS.waitingForTestingValue]: 'Waiting for testing time', + [METRICS_CONSTANTS.designValue]: 'Design time', [METRICS_CONSTANTS.analysisValue]: 'Analysis time', [METRICS_CONSTANTS.reviewValue]: 'Review time', [METRICS_CONSTANTS.blockValue]: 'Block time', [METRICS_CONSTANTS.testingValue]: 'Testing time', + [METRICS_CONSTANTS.waitingForDeploymentValue]: 'Waiting for deployment time', }; export const LEAD_TIME_FOR_CHANGES = { @@ -254,11 +258,13 @@ export const CYCLE_TIME_LIST = [ METRICS_CONSTANTS.cycleTimeEmptyStr, METRICS_CONSTANTS.todoValue, METRICS_CONSTANTS.analysisValue, + METRICS_CONSTANTS.designValue, METRICS_CONSTANTS.inDevValue, METRICS_CONSTANTS.blockValue, METRICS_CONSTANTS.reviewValue, - METRICS_CONSTANTS.waitingValue, + METRICS_CONSTANTS.waitingForTestingValue, METRICS_CONSTANTS.testingValue, + METRICS_CONSTANTS.waitingForDeploymentValue, METRICS_CONSTANTS.doneValue, ]; @@ -268,7 +274,7 @@ export const REWORK_TIME_LIST = [ METRICS_CONSTANTS.inDevValue, METRICS_CONSTANTS.blockValue, METRICS_CONSTANTS.reviewValue, - METRICS_CONSTANTS.waitingValue, + METRICS_CONSTANTS.waitingForTestingValue, METRICS_CONSTANTS.testingValue, ]; @@ -294,26 +300,32 @@ export enum VelocityMetricsName { export enum CycleTimeMetricsName { AVERAGE_CYCLE_TIME = 'Average cycle time', ANALYSIS_PROPORTION = 'Total analysis time / Total cycle time', + DESIGN_PROPORTION = 'Total design time / Total cycle time', DEVELOPMENT_PROPORTION = 'Total development time / Total cycle time', - WAITING_PROPORTION = 'Total waiting for testing time / Total cycle time', BLOCK_PROPORTION = 'Total block time / Total cycle time', REVIEW_PROPORTION = 'Total review time / Total cycle time', + WAITING_FOR_TESTING_PROPORTION = 'Total waiting for testing time / Total cycle time', TESTING_PROPORTION = 'Total testing time / Total cycle time', + WAITING_FOR_DEPLOYMENT_PROPORTION = 'Total waiting for deployment time / Total cycle time', AVERAGE_ANALYSIS_TIME = 'Average analysis time', + AVERAGE_DESIGN_TIME = 'Average design time', AVERAGE_DEVELOPMENT_TIME = 'Average development time', - AVERAGE_WAITING_TIME = 'Average waiting for testing time', AVERAGE_BLOCK_TIME = 'Average block time', AVERAGE_REVIEW_TIME = 'Average review time', + AVERAGE_WAITING_FOR_TESTING_TIME = 'Average waiting for testing time', AVERAGE_TESTING_TIME = 'Average testing time', + AVERAGE_WAITING_FOR_DEPLOYMENT_TIME = 'Average waiting for deployment time', } export const REWORK_TIME_MAPPING = { totalReworkTimes: 'Total rework', fromAnalysis: 'analysis', + fromDesign: 'design', fromInDev: 'in dev', fromBlock: 'block', fromReview: 'review', fromWaitingForTesting: 'waiting for testing', + fromWaitingForDeployment: 'waiting for deployment', fromTesting: 'testing', fromDone: 'done', totalReworkCards: 'Total rework cards', @@ -322,11 +334,13 @@ export const REWORK_TIME_MAPPING = { export const REWORK_BOARD_STATUS: string[] = [ REWORK_TIME_MAPPING.fromAnalysis, + REWORK_TIME_MAPPING.fromDesign, REWORK_TIME_MAPPING.fromInDev, REWORK_TIME_MAPPING.fromBlock, REWORK_TIME_MAPPING.fromWaitingForTesting, REWORK_TIME_MAPPING.fromTesting, REWORK_TIME_MAPPING.fromReview, + REWORK_TIME_MAPPING.fromWaitingForDeployment, REWORK_TIME_MAPPING.fromDone, ]; diff --git a/frontend/src/hooks/reportMapper/cycleTime.ts b/frontend/src/hooks/reportMapper/cycleTime.ts index 4ec5562037..2e7e2b368e 100644 --- a/frontend/src/hooks/reportMapper/cycleTime.ts +++ b/frontend/src/hooks/reportMapper/cycleTime.ts @@ -31,30 +31,46 @@ export const cycleTimeMapper = ({ }; const cycleTimeValue: { [key: string]: ValueWithUnits[] } = { - AVERAGE_CYCLE_TIME: [ + [CycleTimeMetricsName.AVERAGE_CYCLE_TIME]: [ { value: Number(averageCycleTimePerSP.toFixed(2)), unit: ReportSuffixUnits.DaysPerSP }, { value: averageCycleTimePerCard.toFixed(2), unit: ReportSuffixUnits.DaysPerCard, }, ], - ANALYSIS_PROPORTION: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.analysisValue), - DEVELOPMENT_PROPORTION: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.inDevValue), - WAITING_PROPORTION: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.waitingValue), - BLOCK_PROPORTION: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.blockValue), - REVIEW_PROPORTION: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.reviewValue), - TESTING_PROPORTION: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.testingValue), - AVERAGE_ANALYSIS_TIME: getAverageTimeForPerColumn(METRICS_CONSTANTS.analysisValue), - AVERAGE_DEVELOPMENT_TIME: getAverageTimeForPerColumn(METRICS_CONSTANTS.inDevValue), - AVERAGE_WAITING_TIME: getAverageTimeForPerColumn(METRICS_CONSTANTS.waitingValue), - AVERAGE_BLOCK_TIME: getAverageTimeForPerColumn(METRICS_CONSTANTS.blockValue), - AVERAGE_REVIEW_TIME: getAverageTimeForPerColumn(METRICS_CONSTANTS.reviewValue), - AVERAGE_TESTING_TIME: getAverageTimeForPerColumn(METRICS_CONSTANTS.testingValue), + [CycleTimeMetricsName.ANALYSIS_PROPORTION]: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.analysisValue), + [CycleTimeMetricsName.DESIGN_PROPORTION]: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.designValue), + [CycleTimeMetricsName.DEVELOPMENT_PROPORTION]: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.inDevValue), + [CycleTimeMetricsName.WAITING_FOR_TESTING_PROPORTION]: calPerColumnTotalTimeDivTotalTime( + METRICS_CONSTANTS.waitingForTestingValue, + ), + [CycleTimeMetricsName.BLOCK_PROPORTION]: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.blockValue), + [CycleTimeMetricsName.REVIEW_PROPORTION]: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.reviewValue), + [CycleTimeMetricsName.TESTING_PROPORTION]: calPerColumnTotalTimeDivTotalTime(METRICS_CONSTANTS.testingValue), + [CycleTimeMetricsName.WAITING_FOR_DEPLOYMENT_PROPORTION]: calPerColumnTotalTimeDivTotalTime( + METRICS_CONSTANTS.waitingForDeploymentValue, + ), + [CycleTimeMetricsName.AVERAGE_ANALYSIS_TIME]: getAverageTimeForPerColumn(METRICS_CONSTANTS.analysisValue), + [CycleTimeMetricsName.AVERAGE_DESIGN_TIME]: getAverageTimeForPerColumn(METRICS_CONSTANTS.designValue), + [CycleTimeMetricsName.AVERAGE_DEVELOPMENT_TIME]: getAverageTimeForPerColumn(METRICS_CONSTANTS.inDevValue), + [CycleTimeMetricsName.AVERAGE_WAITING_FOR_TESTING_TIME]: getAverageTimeForPerColumn( + METRICS_CONSTANTS.waitingForTestingValue, + ), + [CycleTimeMetricsName.AVERAGE_BLOCK_TIME]: getAverageTimeForPerColumn(METRICS_CONSTANTS.blockValue), + [CycleTimeMetricsName.AVERAGE_REVIEW_TIME]: getAverageTimeForPerColumn(METRICS_CONSTANTS.reviewValue), + [CycleTimeMetricsName.AVERAGE_TESTING_TIME]: getAverageTimeForPerColumn(METRICS_CONSTANTS.testingValue), + [CycleTimeMetricsName.AVERAGE_WAITING_FOR_DEPLOYMENT_TIME]: getAverageTimeForPerColumn( + METRICS_CONSTANTS.waitingForDeploymentValue, + ), }; - Object.entries(CycleTimeMetricsName).map(([key, cycleName]) => { - if (cycleTimeValue[key].length > 0) { - mappedCycleTimeValue.push({ id: mappedCycleTimeValue.length, name: cycleName, valueList: cycleTimeValue[key] }); + Object.values(CycleTimeMetricsName).map((cycleName) => { + if (cycleTimeValue[cycleName].length > 0) { + mappedCycleTimeValue.push({ + id: mappedCycleTimeValue.length, + name: cycleName, + valueList: cycleTimeValue[cycleName], + }); } });