diff --git a/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java b/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java index de16ac9f..19c76364 100644 --- a/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java +++ b/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java @@ -34,7 +34,7 @@ public Object resolveArgument(MethodParameter parameter, Message message) { throw new DTClientErrorException(ClientErrorCode.UNAUTHORIZED_MEMBER); } - String email = authManager.resolveAccessToken(token); + String email = authManager.resolveChairmanToken(token); return authService.getMember(email); } } diff --git a/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java b/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java index b2ee31a6..aeb9c819 100644 --- a/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java +++ b/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java @@ -1,11 +1,14 @@ package com.debatetimer.config.sharing; import com.debatetimer.config.CorsProperties; +import java.time.Duration; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @@ -15,6 +18,12 @@ @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + private static final long SERVER_TO_CLIENT_HEARTBEAT_DURATION = Duration.ofSeconds(10).toMillis(); + private static final long CLIENT_TO_SERVER_HEARTBEAT_DURATION = Duration.ofSeconds(10).toMillis(); + private static final long SOCKJS_HEART_BEAT_DURATION = Duration.ofSeconds(10).toMillis(); + private static final String HEART_BEAT_THREAD_PREFIX = "wss-heartbeat-"; + private static final int HEART_BEAT_THREAD_COUNT = 1; + private final CorsProperties corsProperties; private final WebSocketAuthMemberResolver webSocketAuthMemberResolver; @@ -25,7 +34,9 @@ public void addArgumentResolvers(List resolvers) @Override public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/room", "/chairman"); + registry.enableSimpleBroker("/room", "/chairman") + .setHeartbeatValue(new long[]{SERVER_TO_CLIENT_HEARTBEAT_DURATION, CLIENT_TO_SERVER_HEARTBEAT_DURATION}) + .setTaskScheduler(heartBeatScheduler()); registry.setApplicationDestinationPrefixes("/app"); } @@ -33,6 +44,16 @@ public void configureMessageBroker(MessageBrokerRegistry registry) { public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws") .setAllowedOriginPatterns(corsProperties.getCorsOrigin()) - .withSockJS(); + .withSockJS() + .setHeartbeatTime(SOCKJS_HEART_BEAT_DURATION); + } + + @Bean + public ThreadPoolTaskScheduler heartBeatScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(HEART_BEAT_THREAD_COUNT); + scheduler.setThreadNamePrefix(HEART_BEAT_THREAD_PREFIX); + scheduler.initialize(); + return scheduler; } } diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java new file mode 100644 index 00000000..3231df17 --- /dev/null +++ b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java @@ -0,0 +1,25 @@ +package com.debatetimer.controller.sharing; + +import com.debatetimer.controller.auth.AuthMember; +import com.debatetimer.domain.member.Member; +import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; +import com.debatetimer.service.sharing.SharingService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class SharingRestController { + + private final SharingService sharingService; + + @GetMapping("/api/share/{tableId}/chairman-token") + public ChairmanTokenResponse issueChairmanToken( + @AuthMember Member member, + @PathVariable("tableId") long tableId + ) { + return sharingService.issueChairmanToken(tableId, member); + } +} diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingController.java b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java similarity index 84% rename from src/main/java/com/debatetimer/controller/sharing/SharingController.java rename to src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java index 0216a15b..c2ba0479 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java @@ -1,5 +1,7 @@ package com.debatetimer.controller.sharing; +import com.debatetimer.controller.auth.AuthMember; +import com.debatetimer.domain.member.Member; import com.debatetimer.dto.sharing.request.SharingRequest; import com.debatetimer.dto.sharing.response.SharingResponse; import com.debatetimer.service.sharing.SharingService; @@ -13,13 +15,14 @@ @Controller @RequiredArgsConstructor -public class SharingController { +public class SharingWebSocketController { private final SharingService sharingService; @MessageMapping("/event/{roomId}") @SendTo("/room/{roomId}") public SharingResponse share( + @AuthMember Member member, @DestinationVariable(value = "roomId") long roomId, @Valid @Payload SharingRequest request ) { diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java index a614224f..989bf178 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java @@ -37,4 +37,8 @@ public String resolveAccessToken(String accessToken) { public String resolveRefreshToken(String refreshToken) { return jwtTokenResolver.resolveRefreshToken(refreshToken); } + + public String resolveChairmanToken(String chairmanToken) { + return jwtTokenResolver.resolveChairmanToken(chairmanToken); + } } diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java index ffd28bca..9f3ef75b 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java @@ -23,6 +23,10 @@ public String createRefreshToken(MemberInfo memberInfo) { return createToken(memberInfo, refreshTokenExpiration, TokenType.REFRESH_TOKEN); } + public String createChairmanToken(MemberInfo memberInfo, long expirationSeconds) { + return createToken(memberInfo, Duration.ofSeconds(expirationSeconds), TokenType.CHAIRMAN_TOKEN); + } + private String createToken(MemberInfo memberInfo, Duration expiration, TokenType tokenType) { Date now = new Date(); Date expiredDate = new Date(now.getTime() + expiration.toMillis()); diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java index de5d33f7..15e0d186 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java @@ -23,6 +23,10 @@ public String resolveRefreshToken(String refreshToken) { return resolveToken(refreshToken, TokenType.REFRESH_TOKEN); } + public String resolveChairmanToken(String chairmanToken) { + return resolveToken(chairmanToken, TokenType.CHAIRMAN_TOKEN); + } + private String resolveToken(String token, TokenType tokenType) { try { Claims claims = Jwts.parserBuilder() diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java b/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java index 1112e4b9..9d3a4d0c 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java @@ -3,5 +3,6 @@ public enum TokenType { ACCESS_TOKEN, - REFRESH_TOKEN + REFRESH_TOKEN, + CHAIRMAN_TOKEN } diff --git a/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java b/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java index 2c2e96e7..0132389d 100644 --- a/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java +++ b/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java @@ -61,6 +61,11 @@ public List getCustomizeTimeBoxes(long tableId, Member member) return toCustomizeTimeBoxes(timeBoxEntityList, bellEntityList); } + @Transactional(readOnly = true) + public long getTotalTimeBoxTimes(long tableId) { + return timeBoxRepository.sumTimeByTableId(tableId); + } + private List toCustomizeTimeBoxes( List timeBoxEntities, List bellEntities diff --git a/src/main/java/com/debatetimer/dto/sharing/response/ChairmanTokenResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/ChairmanTokenResponse.java new file mode 100644 index 00000000..c10fc79e --- /dev/null +++ b/src/main/java/com/debatetimer/dto/sharing/response/ChairmanTokenResponse.java @@ -0,0 +1,7 @@ +package com.debatetimer.dto.sharing.response; + +public record ChairmanTokenResponse( + String chairmanToken +) { + +} diff --git a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java index 1a0e524d..89d32ade 100644 --- a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java +++ b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java @@ -13,6 +13,9 @@ public interface CustomizeTimeBoxRepository extends Repository findAllByCustomizeTable(CustomizeTableEntity table); + @Query("SELECT SUM(ctb.time) FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") + long sumTimeByTableId(long tableId); + @Query("DELETE FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") @Modifying(clearAutomatically = true, flushAutomatically = true) void deleteAllByTable(long tableId); diff --git a/src/main/java/com/debatetimer/service/sharing/SharingService.java b/src/main/java/com/debatetimer/service/sharing/SharingService.java index 8002052f..11490a26 100644 --- a/src/main/java/com/debatetimer/service/sharing/SharingService.java +++ b/src/main/java/com/debatetimer/service/sharing/SharingService.java @@ -1,15 +1,26 @@ package com.debatetimer.service.sharing; +import com.debatetimer.controller.tool.jwt.JwtTokenProvider; +import com.debatetimer.domain.customize.CustomizeTable; +import com.debatetimer.domain.member.Member; import com.debatetimer.domain.sharing.TimerEvent; +import com.debatetimer.domainrepository.customize.CustomizeTableDomainRepository; +import com.debatetimer.dto.member.MemberInfo; import com.debatetimer.dto.sharing.request.SharingRequest; +import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; import com.debatetimer.dto.sharing.response.SharingResponse; import com.debatetimer.dto.sharing.response.TimerEventDataResponse; import java.util.Optional; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class SharingService { + private final JwtTokenProvider jwtTokenProvider; + private final CustomizeTableDomainRepository customizeTableDomainRepository; + public SharingResponse share(SharingRequest request) { TimerEvent timerEvent = request.toTimerEvent(); return Optional.ofNullable(timerEvent.getTimerEventData()) @@ -19,4 +30,11 @@ public SharingResponse share(SharingRequest request) { )) .orElse(new SharingResponse(request.eventType(), null)); } + + public ChairmanTokenResponse issueChairmanToken(long tableId, Member member) { + CustomizeTable customizeTable = customizeTableDomainRepository.getByIdAndMember(tableId, member); + long debateTime = customizeTableDomainRepository.getTotalTimeBoxTimes(customizeTable.getId()); + String chairmanToken = jwtTokenProvider.createChairmanToken(new MemberInfo(member), debateTime * 2); + return new ChairmanTokenResponse(chairmanToken); + } } diff --git a/src/test/java/com/debatetimer/controller/BaseDocumentTest.java b/src/test/java/com/debatetimer/controller/BaseDocumentTest.java index bbac2b81..3c139034 100644 --- a/src/test/java/com/debatetimer/controller/BaseDocumentTest.java +++ b/src/test/java/com/debatetimer/controller/BaseDocumentTest.java @@ -15,6 +15,7 @@ import com.debatetimer.service.organization.OrganizationService; import com.debatetimer.service.poll.PollService; import com.debatetimer.service.poll.VoteService; +import com.debatetimer.service.sharing.SharingService; import io.restassured.RestAssured; import io.restassured.builder.RequestSpecBuilder; import io.restassured.filter.log.RequestLoggingFilter; @@ -71,6 +72,9 @@ public abstract class BaseDocumentTest { @MockitoBean protected VoteService voteService; + @MockitoBean + protected SharingService sharingService; + @MockitoBean protected OrganizationService organizationService; diff --git a/src/test/java/com/debatetimer/controller/Tag.java b/src/test/java/com/debatetimer/controller/Tag.java index 5da09bb2..12ac3339 100644 --- a/src/test/java/com/debatetimer/controller/Tag.java +++ b/src/test/java/com/debatetimer/controller/Tag.java @@ -6,6 +6,7 @@ public enum Tag { PARLIAMENTARY_API("Parliamentary Table API"), TIME_BASED_API("Time Based Table API"), CUSTOMIZE_API("Customize Table API"), + SHARING_API("Sharing API"), POLL_API("Poll API"), ORGANIZATION_API("Organization API"); diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java new file mode 100644 index 00000000..ef87c825 --- /dev/null +++ b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java @@ -0,0 +1,59 @@ +package com.debatetimer.controller.sharing; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.payload.JsonFieldType.STRING; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; + +import com.debatetimer.controller.BaseDocumentTest; +import com.debatetimer.controller.RestDocumentationRequest; +import com.debatetimer.controller.RestDocumentationResponse; +import com.debatetimer.controller.Tag; +import com.debatetimer.domain.member.Member; +import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; + +public class SharingDocumentTest extends BaseDocumentTest { + + + @Nested + class IssueChairmanToken { + + private final RestDocumentationRequest requestDocument = request() + .tag(Tag.SHARING_API) + .summary("사회자용 토큰 발급") + .requestHeader(headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")) + .pathParameter(parameterWithName("tableId").description("테이블 id")); + + private final RestDocumentationResponse responseDocument = response() + .responseBodyField( + fieldWithPath("chairmanToken").type(STRING).description("사회자용 토큰") + ); + + @Test + void 사회자_용_토큰_생성_성공() { + long requestTableId = 1L; + ChairmanTokenResponse chairmanTokenResponse = new ChairmanTokenResponse("testToken"); + doReturn(chairmanTokenResponse).when(sharingService) + .issueChairmanToken(eq(requestTableId), any(Member.class)); + + var document = document("sharing/get", 200) + .request(requestDocument) + .response(responseDocument) + .build(); + + given(document) + .contentType(ContentType.JSON) + .headers(EXIST_MEMBER_HEADER) + .pathParam("tableId", String.valueOf(requestTableId)) + .when().get("/api/share/{tableId}/chairman-token") + .then().statusCode(200); + } + } +} diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java similarity index 76% rename from src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java rename to src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java index d644f907..88775492 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java @@ -21,7 +21,7 @@ import org.junit.jupiter.params.provider.NullSource; import org.springframework.messaging.simp.stomp.StompHeaders; -class SharingControllerTest extends BaseStompTest { +class SharingWebSocketControllerTest extends BaseStompTest { @Nested class Share { @@ -31,7 +31,7 @@ class Share { long roomId = 1L; MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); Member member = memberGenerator.generate("example@email.com"); - StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + StompHeaders headers = headerGenerator.generateChairmanTokenHeader("/app/event/" + roomId, member); SharingRequest request = new SharingRequest( TimerEventType.NEXT, new TimerEventInfoRequest( @@ -58,12 +58,34 @@ class Share { ); } + @Test + void 사회자가_아니면_이벤트를_발행할_수_없다() throws ExecutionException, InterruptedException, TimeoutException { + long roomId = 1L; + MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); + Member member = memberGenerator.generate("example@email.com"); + SharingRequest request = new SharingRequest( + TimerEventType.NEXT, + new TimerEventInfoRequest( + CustomizeBoxType.NORMAL, + null, + 2, + 30 + ) + ); + stompSession.subscribe("/room/" + roomId, handler); //청중의 구독 + stompSession.send("/app/event/" + roomId, request); //사회자의 이벤트 발생 + + assertThatThrownBy(() -> handler.getCompletableFuture() + .get(2L, TimeUnit.SECONDS)) + .isInstanceOf(TimeoutException.class); + } + @Test void 사회자가_발생시킨_토론_종료_이벤트를_청중이_공유받는다() throws ExecutionException, InterruptedException, TimeoutException { long roomId = 1L; MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); Member member = memberGenerator.generate("example@email.com"); - StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + StompHeaders headers = headerGenerator.generateChairmanTokenHeader("/app/event/" + roomId, member); SharingRequest request = new SharingRequest(TimerEventType.FINISHED, null); stompSession.subscribe("/room/" + roomId, handler); //청중의 구독 @@ -84,7 +106,7 @@ class Share { long roomId = 1L; MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); Member member = memberGenerator.generate("example@email.com"); - StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + StompHeaders headers = headerGenerator.generateChairmanTokenHeader("/app/event/" + roomId, member); SharingRequest request = new SharingRequest( TimerEventType.NEXT, new TimerEventInfoRequest( diff --git a/src/test/java/com/debatetimer/fixture/HeaderGenerator.java b/src/test/java/com/debatetimer/fixture/HeaderGenerator.java index 70362980..5a76eaac 100644 --- a/src/test/java/com/debatetimer/fixture/HeaderGenerator.java +++ b/src/test/java/com/debatetimer/fixture/HeaderGenerator.java @@ -23,11 +23,11 @@ public Headers generateAccessTokenHeader(Member member) { return new Headers(new Header(HttpHeaders.AUTHORIZATION, accessToken)); } - public StompHeaders generateAccessTokenHeader(String destination, Member member) { - String accessToken = jwtTokenProvider.createAccessToken(new MemberInfo(member)); + public StompHeaders generateChairmanTokenHeader(String destination, Member member) { + String chairmanToken = jwtTokenProvider.createChairmanToken(new MemberInfo(member), 5L); StompHeaders stompHeaders = new StompHeaders(); stompHeaders.setDestination(destination); - stompHeaders.add(HttpHeaders.AUTHORIZATION, accessToken); + stompHeaders.add(HttpHeaders.AUTHORIZATION, chairmanToken); return stompHeaders; } } diff --git a/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java b/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java index 5fcf6b39..93268c2d 100644 --- a/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java +++ b/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java @@ -80,4 +80,22 @@ class DeleteAllByTable { .doesNotThrowAnyException(); } } + + @Nested + class SumTimeByTableId { + + @Test + void 특정_테이블의_타임_박스시간의_합을_반환한다() { + Member chan = memberGenerator.generate("default@gmail.com"); + CustomizeTableEntity debateTable = customizeTableEntityGenerator.generate(chan); + CustomizeTimeBoxEntity timeBox1 = customizeTimeBoxEntityGenerator.generate(debateTable, + CustomizeBoxType.NORMAL, 1, 10); + CustomizeTimeBoxEntity timeBox2 = customizeTimeBoxEntityGenerator.generate(debateTable, + CustomizeBoxType.NORMAL, 2, 20); + + long summedTimeByTableId = customizeTimeBoxRepository.sumTimeByTableId(debateTable.getId()); + + assertThat(summedTimeByTableId).isEqualTo(timeBox1.getTime() + timeBox2.getTime()); + } + } } diff --git a/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java b/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java new file mode 100644 index 00000000..56a1a54a --- /dev/null +++ b/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java @@ -0,0 +1,44 @@ +package com.debatetimer.service.sharing; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.debatetimer.domain.customize.CustomizeBoxType; +import com.debatetimer.domain.member.Member; +import com.debatetimer.entity.customize.CustomizeTableEntity; +import com.debatetimer.exception.custom.DTClientErrorException; +import com.debatetimer.exception.errorcode.ClientErrorCode; +import com.debatetimer.service.BaseServiceTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class SharingServiceTest extends BaseServiceTest { + + @Autowired + private SharingService sharingService; + + @Nested + class IssueChairmanToken { + + @Test + void 사회자_토큰을_할당한다() { + Member member = memberGenerator.generate("email@email.com"); + CustomizeTableEntity tableEntity = customizeTableEntityGenerator.generate(member); + customizeTimeBoxEntityGenerator.generate(tableEntity, CustomizeBoxType.NORMAL, 1); + customizeTimeBoxEntityGenerator.generate(tableEntity, CustomizeBoxType.NORMAL, 2); + + assertThatCode(() -> sharingService.issueChairmanToken(tableEntity.getId(), member)) + .doesNotThrowAnyException(); + } + + @Test + void 회원_소유의_테이블이_아니면_에러가_발생한다() { + Member member = memberGenerator.generate("email@email.com"); + + assertThatThrownBy(() -> sharingService.issueChairmanToken(1L, member)) + .isInstanceOf(DTClientErrorException.class) + .hasMessage(ClientErrorCode.TABLE_NOT_FOUND.getMessage()); + } + } +}