Skip to content

Commit

Permalink
feat: 시험 제출 동시성 문제 테스트
Browse files Browse the repository at this point in the history
  • Loading branch information
alstn113 committed Dec 16, 2024
1 parent f324572 commit b977821
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 7 deletions.
6 changes: 5 additions & 1 deletion server/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ OAUTH_GITHUB_CLIENT_SECRET=
OAUTH_GOOGLE_CLIENT_ID=
OAUTH_GOOGLE_CLIENT_SECRET=

JWT_SECRET_KEY=

DB_URL=
DB_USERNAME=
DB_PASSWORD=

JWT_SECRET_KEY=
MAIL_HOST=
MAIL_USERNAME=
MAIL_PASSWORD=
4 changes: 4 additions & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ dependencies {
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'

// redis
// implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// implementation 'io.lettuce.core:lettuce-core'

// lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public void submit(SubmissionAppRequest request) {
throw new BadRequestException("시험이 공개되지 않았습니다.");
}

//TODO: 존재하지 않는 것에 대한 동시성 문제 aka 따닥 -> Redis 분산락 고려 ?
//TODO: unique 제약조건 examId, memberId ?
if (submissionRepository.existsByExamIdAndMemberId(exam.getId(), member.getId())) {
throw new BadRequestException("이미 제출한 시험입니다.");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.fluffy.submission.domain;

import com.fluffy.global.exception.NotFoundException;
import java.util.List;
import java.util.Optional;
import org.springframework.data.repository.Repository;

public interface SubmissionRepository extends Repository<Submission, Long>, SubmissionRepositoryCustom {

List<Submission> findAll();

void save(Submission submission);

boolean existsByExamIdAndMemberId(Long examId, Long memberId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.fluffy.integration.submission;

import static com.fluffy.auth.domain.OAuth2Provider.GOOGLE;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static org.assertj.core.api.Assertions.assertThat;

import com.fluffy.auth.domain.Member;
import com.fluffy.auth.domain.MemberRepository;
import com.fluffy.exam.domain.Exam;
import com.fluffy.exam.domain.ExamRepository;
import com.fluffy.exam.domain.Question;
import com.fluffy.global.web.Accessor;
import com.fluffy.integration.AbstractIntegrationTest;
import com.fluffy.submission.application.SubmissionService;
import com.fluffy.submission.application.dto.QuestionResponseAppRequest;
import com.fluffy.submission.application.dto.SubmissionAppRequest;
import com.fluffy.submission.domain.Submission;
import com.fluffy.submission.domain.SubmissionRepository;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

class SubmissionServiceIntegrationTest extends AbstractIntegrationTest {

@Autowired
private SubmissionService submissionService;

@Autowired
private ExamRepository examRepository;

@Autowired
private MemberRepository memberRepository;

@Autowired
private SubmissionRepository submissionRepository;

@Test
@Disabled("동시성 문제 해결 방법 미정으로 테스트 비활성화합니다.")
@DisplayName("시험을 제출할 수 있다.")
void submit() throws InterruptedException {
// given
Member member1 = memberRepository.save(new Member("[email protected]", GOOGLE, "123", "ex1", "https://ex1.com"));
Exam exam = Exam.create("시험 제목", member1.getId());
exam.updateQuestions(List.of(Question.shortAnswer("단답형1", "답1")));
exam.publish(null, null);
examRepository.save(exam);

// when
ExecutorService executorService = newFixedThreadPool(2);
SubmissionAppRequest request = new SubmissionAppRequest(
exam.getId(),
List.of(new QuestionResponseAppRequest(List.of("답1"))),
new Accessor(member1.getId())
);
for (int i = 0; i < 2; i++) {
executorService.execute(() -> {
try {
submissionService.submit(request);
} catch (RuntimeException e) {
// ignore
}
});
}

executorService.shutdown();
executorService.awaitTermination(30, TimeUnit.SECONDS);

// then
List<Submission> submissions = submissionRepository.findAll();
assertThat(submissions).hasSize(1);
}
}
20 changes: 14 additions & 6 deletions server/src/test/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ spring:
hibernate:
format_sql: true
highlight_sql: true
mail:
host: smtp.gmail.com
port: 587
username: username
password: password
properties:
mail:
smtp:
connectiontimeout: 5000
timeout: 3000
writetimeout: 5000
auth: true
starttls:
enable: true

api-host: http://localhost:8080
client-host: http://localhost:5173
Expand All @@ -27,9 +41,3 @@ auth:
client-secret: client-secret-client-secret-client-secret-client-secret
redirect-uri: ${api-host}/api/v1/auth/oauth2/callback/github
client-uri: ${client-host}

logging:
level:
org.springframework.orm.jpa: DEBUG
org.springframework.orm.transaction: DEBUG
org.hibernate.orm.jdbc.bind: trace

0 comments on commit b977821

Please sign in to comment.