Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: perf result page #91

Merged
merged 3 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bm-controller/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ dependencies {


implementation 'org.postgresql:postgresql'
compileOnly 'org.projectlombok:lombok'
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public enum ErrorCode {
/**
* 404
*/
TEST_RESULT_NOT_FOUND(404, "테스트 결과가 존재하지 않습니다."),
USER_NOT_FOUND(404, "유저가 존재하지 않습니다."),
USER_ALREADY_EXIST(404, "유저가 이미 존재합니다."),
GROUP_NOT_FOUND(404, "그룹이 존재하지 않습니다."),
Expand All @@ -47,7 +48,7 @@ public enum ErrorCode {
/**
* 500
*/
INTERNAL_SERVER_ERROR(500, "서버 내부 오류"),;
INTERNAL_SERVER_ERROR(500, "서버 내부 오류"), ;

private final int httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import java.util.concurrent.atomic.AtomicReference;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.benchmarker.bmcommon.dto.CommonTestResult;
import org.benchmarker.bmcommon.dto.MTTFBInfo;
import org.benchmarker.bmcommon.dto.TPSInfo;
import org.benchmarker.bmcontroller.common.controller.annotation.GlobalControllerModel;
import org.benchmarker.bmcontroller.common.model.BaseTime;
import org.benchmarker.bmcontroller.template.model.TestExecution;
import org.benchmarker.bmcontroller.template.model.TestMttfb;
Expand All @@ -27,6 +29,7 @@
@Controller
@Slf4j
@RequiredArgsConstructor
@GlobalControllerModel
public class ResultController {

private final TestExecutionService testExecutionService;
Expand Down Expand Up @@ -55,7 +58,7 @@ public String showChart(
List<MTTFBInfo> mttfbInfoList = new ArrayList<>();
List<TPSInfo> tpsInfoList = new ArrayList<>();

AtomicReference<TestResult> lastTestResult = new AtomicReference<TestResult>();
AtomicReference<TestResult> resultSets = new AtomicReference<TestResult>();

// TODO : N+1 prob. n.n
testResults.stream().forEach(testResult -> {
Expand All @@ -68,9 +71,12 @@ public String showChart(
TPSInfo.builder().timestamp(testTps.getCreatedAt()).tps(testTps.getTransaction())
.build());
assert false;
lastTestResult.set(testResult);
resultSets.set(testResult);
});

CommonTestResult lastTestResult = testExecutionService.getLastTestResult(testId);

model.addAttribute("commonTestResult",lastTestResult);
model.addAttribute("mttfbInfoList", mttfbInfoList);
model.addAttribute("tpsInfoList", tpsInfoList);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
package org.benchmarker.bmcontroller.template.model;

import jakarta.persistence.*;
import lombok.*;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import java.time.LocalDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.benchmarker.bmagent.AgentStatus;
import org.benchmarker.bmcontroller.common.model.BaseTime;
import org.benchmarker.bmcontroller.template.controller.dto.TestResultResponseDto;

import java.time.LocalDateTime;
import java.util.List;


@Slf4j
@Getter
Expand All @@ -24,10 +37,6 @@ public class TestResult extends BaseTime {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

// @ManyToOne(fetch = FetchType.EAGER)
// @JoinColumn(name = "test_template_id", referencedColumnName = "id", nullable = false)
// private TestTemplate testTemplate;

private Integer totalRequest;

private Integer totalError;
Expand Down Expand Up @@ -71,4 +80,5 @@ public TestResultResponseDto convertToResponseDto() {
.build();
}


}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.benchmarker.bmcontroller.template.repository;

import java.util.List;
import java.util.UUID;
import org.benchmarker.bmcontroller.template.model.TestResult;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
Expand All @@ -11,4 +13,7 @@ public interface TestResultRepository extends JpaRepository<TestResult, Integer>

@Query("select tr from TestResult tr where tr.testExecution.testTemplate.id = :templateId")
TestResult findByTestTemplate(@Param("templateId") Integer templateId);

@Query("select tr from TestResult tr where tr.testExecution.id = :testExecutionId order by tr.createdAt desc")
List<TestResult> findAllByTestExecutionId(@Param("testExecutionId") UUID testExecutionId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.benchmarker.bmagent.AgentStatus;
import org.benchmarker.bmcommon.dto.CommonTestResult;
import org.benchmarker.bmcontroller.common.error.ErrorCode;
import org.benchmarker.bmcontroller.common.error.GlobalException;
import org.benchmarker.bmcontroller.preftest.common.TestInfo;
import org.benchmarker.bmcontroller.template.model.TestExecution;
import org.benchmarker.bmcontroller.template.model.TestResult;
import org.benchmarker.bmcontroller.template.model.TestTemplate;
import org.benchmarker.bmcontroller.template.repository.TestExecutionRepository;
import org.benchmarker.bmcontroller.template.repository.TestResultRepository;
import org.benchmarker.bmcontroller.template.repository.TestTemplateRepository;
import org.benchmarker.bmcontroller.template.service.utils.CommonDtoConversion;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
Expand All @@ -22,6 +26,7 @@ public class TestExecutionService {

private final TestExecutionRepository testExecutionRepository;
private final TestTemplateRepository testTemplateRepository;
private final TestResultRepository testResultRepository;

/**
* 테스트 시작 전 TestExecution 을 DB 에 저장합니다.
Expand All @@ -47,6 +52,18 @@ public TestExecution getTest(String id) {
.orElseThrow(() -> new GlobalException(ErrorCode.TEST_NOT_FOUND));
}

@Transactional(readOnly = true)
public CommonTestResult getLastTestResult(String testId) {
List<TestResult> findResults = testResultRepository.findAllByTestExecutionId(
UUID.fromString(testId));
if (findResults.isEmpty()) {
throw new GlobalException(ErrorCode.TEST_RESULT_NOT_FOUND);
}
// get latest test result
TestResult testResult = findResults.get(0);
return CommonDtoConversion.convertToCommonTestResult(testResult);
}

@Transactional(readOnly = true)
public Page<TestExecution> getTestsPageable(Pageable pageable, Integer templateId) {
return testExecutionRepository.findAllByTestTemplateId(templateId, pageable);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.benchmarker.bmcontroller.template.service.utils;

import java.time.Duration;
import java.util.stream.Collectors;
import org.benchmarker.bmcommon.dto.CommonTestResult;
import org.benchmarker.bmcontroller.template.model.TestResult;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
* convert Entity to DTO
*/
@Transactional(propagation = Propagation.REQUIRED, readOnly = true, rollbackFor = Exception.class)
public class CommonDtoConversion {

// TODO : 다량의 정보를 불러오는 만큼 캐싱 필요
public static CommonTestResult convertToCommonTestResult(TestResult testResult) {
// check parent transaction or exception
ParentTXCheck.IsParentTransactionActive();

return CommonTestResult.builder()
.groupId(testResult.getTestExecution().getTestTemplate().getUserGroup().getId())
.testStatus(testResult.getAgentStatus())
.totalRequests(testResult.getTotalRequest())
.totalErrors(testResult.getTotalError())
.totalUsers(testResult.getTestExecution().getTestTemplate().getVuser())
.totalSuccess(testResult.getTotalSuccess())
.url(testResult.getTestExecution().getTestTemplate().getUrl())
.tpsAverage(testResult.getTpsAvg())
.mttfbAverage(testResult.getMttbfbAvg())
.startedAt(testResult.getStartedAt().toString())
.finishedAt(testResult.getFinishedAt().toString())
.totalDuration(
Duration.between(testResult.getStartedAt(), testResult.getFinishedAt()).toString())
.statusCodeCount(testResult.getTestStatuses().stream().collect(
Collectors.toMap((status) -> status.getCode().toString(),
(status) -> status.getCount())))
// TODO : 현재 mttfb, tps percentile 정보가 저장되어있지 않고 그때그때 연산필요.
// TODO : TestStatus 가 GET, POST 와 같은 정보를 저장하고 있음. 이는 맞지 않는 스키마이며 HTTP Status Code 를 저장해야함.
// HTTP Status Code 는 200, 201, 400, 404, 500 등이 있음. 따라서 엔티티 내부 필드에서 int 로 저장해야함.
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.benchmarker.bmcontroller.template.service.utils;

import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
* check parent transaction
*/
public class ParentTXCheck {

/**
* check parent transaction
*
* @throws IllegalStateException if parent transaction is not active or not exist
*/
public static void IsParentTransactionActive() {
boolean actualTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스프링에선 트렌젝션을 계층 구조로 관리한다는 것과 부모의 트렌잭션 활성화 여부를 판별 할 수 있는 것도 처음알았네요 !! 👍

if (!actualTransactionActive) {
throw new IllegalStateException("Parent transaction is not active");
}
}
}
18 changes: 11 additions & 7 deletions bm-controller/src/main/resources/static/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,19 @@ button[type="submit"]:hover {

#agentInfoContainer {
display: flex;
flex-wrap: wrap; /* 요소들이 넘칠 경우 줄 바꿈 */
background-color: #f8f9fa; /* 배경색 설정 */
padding: 10px; /* 내부 여백 설정 */
align-items: center; /* 요소들을 수직 가운데 정렬 */
flex-wrap: wrap;
flex-direction: row;
background-color: #f8f9fa;
padding: 10px;
align-items: center;
align-self: center;
border-radius: 5px; /* 테두리 모서리를 둥글게 만듦 */
border-radius: 5px;
margin-bottom: 0px;
border: 1px solid #ced4da; /* 테두리 설정 */
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 그림자 효과 추가 */
border: 1px solid #ced4da;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
height: 40px; /* Set a specific height */
overflow-y: auto; /* Add scrollbar if content exceeds container height */
visibility: hidden;
}

.agent-info {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="/css/bar.css">
<link rel="stylesheet" type="text/css" href="/css/styles.css">

</head>
<body>

<!-- Current user status bar -->
<div th:fragment="agentStatus" id="agentInfoContainer">
<div th:fragment="agentStatus" id="agentInfoContainer" style="visibility: hidden;">

<script>
console.log("agentStatus");

var sockJs = new SockJS("/gs-guide-websocket");
var stompClient = Stomp.over(sockJs);
stompClient.debug = null;
Expand Down Expand Up @@ -97,13 +96,20 @@
console.error('Error with websocket', error);
};

console.log(stompClient);
const toggleButton = document.getElementById('toggleButton');
const agentContainer = document.getElementById('agentInfoContainer');

toggleButton.addEventListener('click', function() {
// Toggle the display property of the agent status container
if (agentContainer.style.visibility === 'hidden') {
agentContainer.style.visibility = 'visible';
} else {
agentContainer.style.visibility = 'hidden';
}
});

</script>
</div>


</body>
</html>


Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@
<link rel="stylesheet" type="text/css" href="/css/styles.css">
<link rel="stylesheet" type="text/css" href="/css/bar.css">
<!-- <script src="/js/connectStomp.js"></script>-->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
.charts-container {
display: grid;
grid-template-columns: 1fr 1fr; /* Two equal columns */
grid-gap: 20px; /* Gap between charts */
padding: 20px;
}
.chart-container {
width: 100%;
}
canvas {
width: 100%;
padding: 20px;
height: auto !important;
}
</style>
</head>
<body>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<div th:fragment="currentUser" class="status-bar" th:classappend="${currentUser} ? 'logged-in' : ''">
<link rel="stylesheet" type="text/css" href="/css/bar.css">
<a th:href="@{/}" class="home-link">Benchmark</a>
<button id="toggleButton">see agents</button>
<p th:if="${currentUser}" class="user-text">
Logged in as:
<a th:href="@{'/users/' + ${currentUser.id}}" class="user-link" th:text="${currentUser.id}"></a>
Expand Down
10 changes: 4 additions & 6 deletions bm-controller/src/main/resources/templates/group/list.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Group Information</title>
<link rel="stylesheet" type="text/css" href="../css/styles.css">
</head>
<body>
<header th:replace="~{fragments/commonHeader :: common('My Groups')}"></header>

<div th:replace="fragments/currentUserFragment :: currentUser"></div>
<div th:replace="~{fragments/agentStatus :: agentStatus}"></div>

<h1>Groups</h1>

<div class="container">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Register Group</title>
<link rel="stylesheet" type="text/css" href="../css/styles.css">
</head>
<body>
<header th:replace="~{fragments/commonHeader :: common('Register Group')}"></header>
<div th:replace="fragments/currentUserFragment :: currentUser"></div>
<div th:replace="~{fragments/agentStatus :: agentStatus}"></div>

<div class="container">
<h1>Register Group</h1>
Expand Down
Loading
Loading