From 5b2f0127324f9e9fa11a771aab610fb0ae80b65f Mon Sep 17 00:00:00 2001 From: Wang Shiji Date: Thu, 26 Sep 2024 01:08:05 +0800 Subject: [PATCH] rewrite the page logic for quiz apis --- api/quiz_ms-quiz-openapi.yaml | 245 +-------------- .../quiz_ms/controller/QuizController.java | 8 +- .../quiz_ms/controller/model/MCQResponse.java | 25 ++ .../controller/model/QuizListResponse.java | 6 +- .../controller/model/QuizResponse.java | 8 +- .../com/quemistry/quiz_ms/model/Quiz.java | 11 - .../quemistry/quiz_ms/model/QuizAttempt.java | 11 +- .../repository/QuizAttemptRepository.java | 7 + .../quiz_ms/service/QuizService.java | 165 +++++----- .../controller/QuizControllerTest.java | 86 ++---- .../quiz_ms/service/QuizServiceTest.java | 290 +++++++++--------- 11 files changed, 312 insertions(+), 550 deletions(-) diff --git a/api/quiz_ms-quiz-openapi.yaml b/api/quiz_ms-quiz-openapi.yaml index 6ad14d7..9b37b2d 100644 --- a/api/quiz_ms-quiz-openapi.yaml +++ b/api/quiz_ms-quiz-openapi.yaml @@ -43,179 +43,6 @@ paths: '*/*': schema: $ref: "#/components/schemas/QuizResponse" - /v1/quizzes/{id}: - get: - summary: "GET v1/quizzes/{id}" - operationId: "getQuiz" - parameters: - - name: "id" - in: "path" - required: true - schema: - type: "integer" - format: "int64" - - name: "pageNumber" - in: "query" - required: true - schema: - type: "integer" - format: "int32" - - name: "pageSize" - in: "query" - required: true - schema: - type: "integer" - format: "int32" - - name: "x-user-id" - in: "header" - required: true - schema: - type: "string" - - name: "x-user-email" - in: "header" - required: true - schema: - type: "string" - - name: "x-user-roles" - in: "header" - required: true - schema: - type: "string" - responses: - "200": - description: "OK" - content: - '*/*': - schema: - $ref: "#/components/schemas/QuizResponse" - /v1/quizzes/me/in-progress: - get: - summary: "GET v1/quizzes/me/in-progress" - operationId: "getInProgressQuiz" - parameters: - - name: "pageNumber" - in: "query" - required: true - schema: - type: "integer" - format: "int32" - - name: "pageSize" - in: "query" - required: true - schema: - type: "integer" - format: "int32" - - name: "x-user-id" - in: "header" - required: true - schema: - type: "string" - - name: "x-user-email" - in: "header" - required: true - schema: - type: "string" - - name: "x-user-roles" - in: "header" - required: true - schema: - type: "string" - responses: - "200": - description: "OK" - content: - '*/*': - schema: - $ref: "#/components/schemas/QuizResponse" - /v1/quizzes/me/completed: - get: - summary: "GET v1/quizzes/me/completed" - operationId: "getCompletedQuiz" - parameters: - - name: "pageNumber" - in: "query" - required: true - schema: - type: "integer" - format: "int32" - - name: "pageSize" - in: "query" - required: true - schema: - type: "integer" - format: "int32" - - name: "x-user-id" - in: "header" - required: true - schema: - type: "string" - - name: "x-user-email" - in: "header" - required: true - schema: - type: "string" - - name: "x-user-roles" - in: "header" - required: true - schema: - type: "string" - responses: - "200": - description: "OK" - content: - '*/*': - schema: - $ref: "#/components/schemas/QuizListResponse" - /v1/quizzes/{id}/mcqs/{mcqId}/attempt: - put: - summary: "PUT v1/quizzes/{id}/mcqs/{mcqId}/attempt" - operationId: "updateAttempt" - parameters: - - name: "id" - in: "path" - required: true - schema: - type: "integer" - format: "int64" - - name: "mcqId" - in: "path" - required: true - schema: - type: "integer" - format: "int64" - - name: "x-user-id" - in: "header" - required: true - schema: - type: "string" - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/AttemptRequest" - required: true - responses: - "204": - description: "No Content" - /v1/quizzes/{id}/abandon: - patch: - summary: "PATCH v1/quizzes/{id}/abandon" - operationId: "abandonQuiz" - parameters: - - name: "id" - in: "path" - required: true - schema: - type: "integer" - format: "int64" - - name: "x-user-id" - in: "header" - required: true - schema: - type: "string" - responses: - "204": - description: "No Content" components: schemas: QuizRequest: @@ -271,6 +98,12 @@ components: MCQResponse: type: "object" properties: + attemptOption: + type: "integer" + format: "int32" + attemptOn: + type: "string" + format: "date-time" id: type: "integer" format: "int64" @@ -305,12 +138,6 @@ components: format: "date-time" createdBy: type: "string" - attemptOption: - type: "integer" - format: "int32" - attemptOn: - type: "string" - format: "date-time" QuizResponse: type: "object" properties: @@ -318,9 +145,7 @@ components: type: "integer" format: "int64" mcqs: - type: "array" - items: - $ref: "#/components/schemas/MCQResponse" + $ref: "#/components/schemas/MCQResponse" status: type: "string" enum: @@ -330,59 +155,3 @@ components: points: type: "integer" format: "int32" - pageNumber: - type: "integer" - format: "int32" - pageSize: - type: "integer" - format: "int32" - totalPages: - type: "integer" - format: "int32" - totalRecords: - type: "integer" - format: "int64" - SimpleQuizResponse: - type: "object" - properties: - id: - type: "integer" - format: "int64" - mcqs: - type: "array" - items: - $ref: "#/components/schemas/MCQResponse" - status: - type: "string" - enum: - - "IN_PROGRESS" - - "COMPLETED" - - "ABANDONED" - points: - type: "integer" - format: "int32" - QuizListResponse: - type: "object" - properties: - pageNumber: - type: "integer" - format: "int32" - pageSize: - type: "integer" - format: "int32" - totalPages: - type: "integer" - format: "int32" - totalRecords: - type: "integer" - format: "int64" - quizzes: - type: "array" - items: - $ref: "#/components/schemas/SimpleQuizResponse" - AttemptRequest: - type: "object" - properties: - attemptOption: - type: "integer" - format: "int32" diff --git a/src/main/java/com/quemistry/quiz_ms/controller/QuizController.java b/src/main/java/com/quemistry/quiz_ms/controller/QuizController.java index 07ad24c..aa9fcdc 100644 --- a/src/main/java/com/quemistry/quiz_ms/controller/QuizController.java +++ b/src/main/java/com/quemistry/quiz_ms/controller/QuizController.java @@ -2,10 +2,7 @@ import static org.springframework.http.HttpStatus.NO_CONTENT; -import com.quemistry.quiz_ms.controller.model.QuizAttemptRequest; -import com.quemistry.quiz_ms.controller.model.QuizListResponse; -import com.quemistry.quiz_ms.controller.model.QuizRequest; -import com.quemistry.quiz_ms.controller.model.QuizResponse; +import com.quemistry.quiz_ms.controller.model.*; import com.quemistry.quiz_ms.model.UserContext; import com.quemistry.quiz_ms.service.QuizService; import jakarta.validation.constraints.Email; @@ -13,6 +10,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.PositiveOrZero; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.*; @Slf4j @@ -62,7 +60,7 @@ public QuizResponse getInProgressQuiz( } @GetMapping("me/completed") - public QuizListResponse getCompletedQuiz( + public Page getCompletedQuiz( @RequestHeader("x-user-id") @NotBlank String studentId, @RequestHeader("x-user-email") @Email String studentEmail, @RequestHeader("x-user-roles") @NotBlank String roles, diff --git a/src/main/java/com/quemistry/quiz_ms/controller/model/MCQResponse.java b/src/main/java/com/quemistry/quiz_ms/controller/model/MCQResponse.java index 42b1cfc..866ac34 100644 --- a/src/main/java/com/quemistry/quiz_ms/controller/model/MCQResponse.java +++ b/src/main/java/com/quemistry/quiz_ms/controller/model/MCQResponse.java @@ -1,6 +1,7 @@ package com.quemistry.quiz_ms.controller.model; import com.quemistry.quiz_ms.client.model.MCQDto; +import com.quemistry.quiz_ms.model.QuizAttempt; import java.util.Date; import lombok.*; import lombok.experimental.SuperBuilder; @@ -13,4 +14,28 @@ public class MCQResponse extends MCQDto { private Integer attemptOption; private Date attemptOn; + + public static MCQResponse from(QuizAttempt attempt, MCQDto mcqDto) { + MCQResponseBuilder builder = MCQResponse.builder(); + builder + .id(attempt.getMcqId()) + .attemptOption(attempt.getOptionNo()) + .attemptOn(attempt.getAttemptTime()); + + if (mcqDto != null) { + builder + .stem(mcqDto.getStem()) + .options(mcqDto.getOptions()) + .topics(mcqDto.getTopics()) + .skills(mcqDto.getSkills()) + .status(mcqDto.getStatus()) + .publishedOn(mcqDto.getPublishedOn()) + .publishedBy(mcqDto.getPublishedBy()) + .closedOn(mcqDto.getClosedOn()) + .closedBy(mcqDto.getClosedBy()) + .createdOn(mcqDto.getCreatedOn()) + .createdBy(mcqDto.getCreatedBy()); + } + return builder.build(); + } } diff --git a/src/main/java/com/quemistry/quiz_ms/controller/model/QuizListResponse.java b/src/main/java/com/quemistry/quiz_ms/controller/model/QuizListResponse.java index 36e57e3..ce83aa7 100644 --- a/src/main/java/com/quemistry/quiz_ms/controller/model/QuizListResponse.java +++ b/src/main/java/com/quemistry/quiz_ms/controller/model/QuizListResponse.java @@ -10,11 +10,7 @@ @NoArgsConstructor @AllArgsConstructor @Builder -public class QuizListResponse { - private Integer pageNumber; - private Integer pageSize; - private Integer totalPages; - private Long totalRecords; +class QuizListResponse { private List quizzes; } diff --git a/src/main/java/com/quemistry/quiz_ms/controller/model/QuizResponse.java b/src/main/java/com/quemistry/quiz_ms/controller/model/QuizResponse.java index 2ace053..a854211 100644 --- a/src/main/java/com/quemistry/quiz_ms/controller/model/QuizResponse.java +++ b/src/main/java/com/quemistry/quiz_ms/controller/model/QuizResponse.java @@ -1,11 +1,11 @@ package com.quemistry.quiz_ms.controller.model; import com.quemistry.quiz_ms.model.QuizStatus; -import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.data.domain.Page; @Data @NoArgsConstructor @@ -13,11 +13,7 @@ @Builder public class QuizResponse { private Long id; - private List mcqs; + private Page mcqs; private QuizStatus status; private Integer points; - private Integer pageNumber; - private Integer pageSize; - private Integer totalPages; - private Long totalRecords; } diff --git a/src/main/java/com/quemistry/quiz_ms/model/Quiz.java b/src/main/java/com/quemistry/quiz_ms/model/Quiz.java index ae0d70b..5beaed4 100644 --- a/src/main/java/com/quemistry/quiz_ms/model/Quiz.java +++ b/src/main/java/com/quemistry/quiz_ms/model/Quiz.java @@ -1,13 +1,10 @@ package com.quemistry.quiz_ms.model; import static com.quemistry.quiz_ms.model.QuizStatus.*; -import static jakarta.persistence.CascadeType.ALL; import static jakarta.persistence.GenerationType.IDENTITY; import jakarta.persistence.*; -import java.util.ArrayList; import java.util.Date; -import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -33,24 +30,16 @@ public class Quiz { private Date updatedOn; - @OneToMany(mappedBy = "quiz", cascade = ALL, orphanRemoval = true) - private List attempts; - public static Quiz create(String studentId) { Date now = new Date(); return Quiz.builder() .status(IN_PROGRESS) .studentId(studentId) - .attempts(new ArrayList<>()) .createdOn(now) .updatedOn(now) .build(); } - public void addAttempts(List mcqIds) { - mcqIds.forEach(mcqId -> this.attempts.add(QuizAttempt.create(this, mcqId))); - } - public void complete() { this.status = COMPLETED; this.updatedOn = new Date(); diff --git a/src/main/java/com/quemistry/quiz_ms/model/QuizAttempt.java b/src/main/java/com/quemistry/quiz_ms/model/QuizAttempt.java index 498b451..861899d 100644 --- a/src/main/java/com/quemistry/quiz_ms/model/QuizAttempt.java +++ b/src/main/java/com/quemistry/quiz_ms/model/QuizAttempt.java @@ -1,7 +1,5 @@ package com.quemistry.quiz_ms.model; -import static jakarta.persistence.FetchType.LAZY; - import jakarta.persistence.*; import java.io.Serializable; import java.util.Date; @@ -24,18 +22,13 @@ public class QuizAttempt { @Id private Long mcqId; - @ManyToOne(fetch = LAZY) - @JoinColumn(name = "quiz_id", insertable = false, updatable = false) - private Quiz quiz; - private Integer optionNo; private Date attemptTime; - public static QuizAttempt create(Quiz quiz, Long mcqId) { + public static QuizAttempt create(Long quizId, Long mcqId) { return QuizAttempt.builder() - .quiz(quiz) - .quizId(quiz.getId()) + .quizId(quizId) .mcqId(mcqId) .optionNo(null) .attemptTime(null) diff --git a/src/main/java/com/quemistry/quiz_ms/repository/QuizAttemptRepository.java b/src/main/java/com/quemistry/quiz_ms/repository/QuizAttemptRepository.java index a6b4bb0..1013aca 100644 --- a/src/main/java/com/quemistry/quiz_ms/repository/QuizAttemptRepository.java +++ b/src/main/java/com/quemistry/quiz_ms/repository/QuizAttemptRepository.java @@ -2,11 +2,18 @@ import com.quemistry.quiz_ms.model.QuizAttempt; import com.quemistry.quiz_ms.model.QuizAttempt.QuizAttemptId; +import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; public interface QuizAttemptRepository extends JpaRepository { Optional findByQuizIdAndMcqId(Long quizId, Long mcqId); + List findAllByQuizIdIn(List quizIds); + boolean existsByQuizIdAndOptionNoIsNull(Long quizId); + + Page findPageByQuizId(Long id, Pageable page); } diff --git a/src/main/java/com/quemistry/quiz_ms/service/QuizService.java b/src/main/java/com/quemistry/quiz_ms/service/QuizService.java index 23b9bb6..5d566ad 100644 --- a/src/main/java/com/quemistry/quiz_ms/service/QuizService.java +++ b/src/main/java/com/quemistry/quiz_ms/service/QuizService.java @@ -21,10 +21,12 @@ import com.quemistry.quiz_ms.repository.QuizRepository; import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; @@ -56,6 +58,7 @@ public QuizResponse createQuiz(UserContext userContext, QuizRequest quizRequest) Quiz quiz = Quiz.create(userContext.getUserId()); quiz = quizRepository.save(quiz); + long quizId = quiz.getId(); RetrieveMCQResponse retrieveMCQRequests = questionClient.retrieveMCQs( @@ -71,28 +74,20 @@ public QuizResponse createQuiz(UserContext userContext, QuizRequest quizRequest) List mcqIds = retrieveMCQRequests.getMcqs().stream().map(MCQDto::getId).toList(); - quiz.addAttempts(mcqIds); - quiz = quizRepository.save(quiz); - - List mcqResponses = - retrieveMCQRequests.getMcqs().stream() - .map(mcqMapper::toMCQResponse) - .limit(quizRequest.getPageSize()) - .collect(Collectors.toList()); + mcqIds.parallelStream() + .forEach(mcqId -> attemptRepository.save(QuizAttempt.create(quizId, mcqId))); - Long totalRecords = - Math.min(retrieveMCQRequests.getTotalRecords(), quizRequest.getTotalSize().intValue()); - Integer totalPages = (int) Math.ceil((double) totalRecords / quizRequest.getPageSize()); + long totalRecords = Math.min(retrieveMCQRequests.getTotalRecords(), quizRequest.getTotalSize()); + Page mcqs = + new PageImpl<>( + retrieveMCQRequests.getMcqs().stream() + .map(mcqMapper::toMCQResponse) + .limit(quizRequest.getPageSize()) + .collect(Collectors.toList()), + PageRequest.of(0, quizRequest.getPageSize()), + totalRecords); - return QuizResponse.builder() - .id(quiz.getId()) - .mcqs(mcqResponses) - .status(quiz.getStatus()) - .pageNumber(0) - .pageSize(quizRequest.getPageSize()) - .totalPages(totalPages) - .totalRecords(totalRecords) - .build(); + return QuizResponse.builder().id(quizId).mcqs(mcqs).status(quiz.getStatus()).build(); } public QuizResponse getQuiz( @@ -109,23 +104,12 @@ public QuizResponse getInProgressQuiz( return convertQuiz(pageNumber, pageSize, quiz, userContext); } - public QuizListResponse getCompletedQuiz( + public Page getCompletedQuiz( UserContext userContext, Integer pageNumber, Integer pageSize) { - Page quizzes = + return getQuizDetail( + userContext, quizRepository.findPageByStudentIdAndStatus( - userContext.getUserId(), COMPLETED, PageRequest.of(pageNumber, pageSize)); - - int quizNumber = quizzes.getNumberOfElements(); - List quizResponses = - quizNumber > 0 ? getQuizDetail(userContext, quizzes) : List.of(); - - return QuizListResponse.builder() - .pageNumber(pageNumber) - .pageSize(pageSize) - .totalPages(quizzes.getTotalPages()) - .totalRecords(quizzes.getTotalElements()) - .quizzes(quizResponses) - .build(); + userContext.getUserId(), COMPLETED, PageRequest.of(pageNumber, pageSize))); } public void updateAttempt(Long quizId, Long mcqId, String studentId, Integer attemptOption) { @@ -146,7 +130,10 @@ public void updateAttempt(Long quizId, Long mcqId, String studentId, Integer att attemptRepository.save(attempt); if (!attemptRepository.existsByQuizIdAndOptionNoIsNull(quizId)) { - Quiz quiz = attempt.getQuiz(); + Quiz quiz = + quizRepository + .findOneByIdAndStudentId(quizId, studentId) + .orElseThrow(() -> new NotFoundException("Quiz not found")); quiz.complete(); quizRepository.save(quiz); } @@ -167,34 +154,41 @@ public void abandonQuiz(Long id, String studentId) { quizRepository.save(quizEntity); } - private List getQuizDetail(UserContext userContext, Page quizzes) { + private Page getQuizDetail(UserContext userContext, Page quizzes) { + List attempts = + attemptRepository.findAllByQuizIdIn(quizzes.stream().map(Quiz::getId).toList()); List mcqs = - questionClient - .retrieveMCQsByIds( - RetrieveMCQByIdsRequest.builder() - .ids( - quizzes.stream() - .flatMap(quiz -> quiz.getAttempts().stream().map(QuizAttempt::getMcqId)) - .toList()) - .pageNumber(0) - .pageSize(quizzes.getNumberOfElements() * 60) - .build(), - userContext.getUserId(), - userContext.getUserEmail(), - userContext.getUserRoles()) - .getMcqs(); - return quizzes.stream() - .map( - quiz -> { - List quizMcqs = getMcqResponses(mcqs, quiz.getAttempts()); - return SimpleQuizResponse.builder() - .id(quiz.getId()) - .status(quiz.getStatus()) - .mcqs(quizMcqs) - .points(calculatePoints(quizMcqs)) - .build(); - }) - .collect(Collectors.toList()); + quizzes.isEmpty() + ? List.of() + : questionClient + .retrieveMCQsByIds( + RetrieveMCQByIdsRequest.builder() + .ids( + attempts.stream() + .map(QuizAttempt::getMcqId) + .collect(Collectors.toList())) + .pageNumber(0) + .pageSize(quizzes.getNumberOfElements() * 60) + .build(), + userContext.getUserId(), + userContext.getUserEmail(), + userContext.getUserRoles()) + .getMcqs(); + return quizzes.map( + quiz -> { + List quizMcqs = + getMcqResponses( + mcqs, + attempts.stream() + .filter(attempt -> attempt.getQuizId().equals(quiz.getId())) + .collect(Collectors.toList())); + return SimpleQuizResponse.builder() + .id(quiz.getId()) + .status(quiz.getStatus()) + .mcqs(quizMcqs) + .points(calculatePoints(quizMcqs)) + .build(); + }); } private QuizResponse convertQuiz( @@ -203,11 +197,13 @@ private QuizResponse convertQuiz( throw new NotFoundException("Quiz not found"); } Quiz quiz = quizResponse.get(); + Page attempts = + attemptRepository.findPageByQuizId(quiz.getId(), PageRequest.of(pageNumber, pageSize)); RetrieveMCQResponse mcqs = questionClient.retrieveMCQsByIds( RetrieveMCQByIdsRequest.builder() - .ids(quiz.getAttempts().stream().map(QuizAttempt::getMcqId).toList()) + .ids(attempts.stream().map(QuizAttempt::getMcqId).toList()) .pageNumber(0) .pageSize(60) .build(), @@ -215,36 +211,35 @@ private QuizResponse convertQuiz( userContext.getUserEmail(), userContext.getUserRoles()); - List mcqResponses = getMcqResponses(mcqs.getMcqs(), quiz.getAttempts()); - Integer points = (quiz.getStatus() == COMPLETED) ? calculatePoints(mcqResponses) : null; + Integer points = + (quiz.getStatus() == COMPLETED) + ? calculatePoints(getPageMcqResponses(mcqs.getMcqs(), attempts).toList()) + : null; return QuizResponse.builder() .id(quiz.getId()) - .mcqs(mcqResponses) + .mcqs(getPageMcqResponses(mcqs.getMcqs(), attempts)) .status(quiz.getStatus()) - .pageNumber(pageNumber) - .pageSize(pageSize) - .totalPages(mcqs.getTotalPages()) - .totalRecords(mcqs.getTotalRecords()) .points(points) .build(); } + private Page getPageMcqResponses(List mcqs, Page attempts) { + return attempts.map(getQuizAttemptMCQResponse(mcqs)); + } + private List getMcqResponses(List mcqs, List attempts) { - return attempts.stream() - .map( - attempt -> { - MCQDto mcqDto = - mcqs.stream() - .filter(mcq -> mcq.getId().equals(attempt.getMcqId())) - .findFirst() - .orElse(null); - MCQResponse response = mcqMapper.toMCQResponse(mcqDto); - response.setAttemptOption(attempt.getOptionNo()); - response.setAttemptOn(attempt.getAttemptTime()); - return response; - }) - .toList(); + return attempts.stream().map(getQuizAttemptMCQResponse(mcqs)).collect(Collectors.toList()); + } + + private static Function getQuizAttemptMCQResponse(List mcqs) { + return attempt -> + MCQResponse.from( + attempt, + mcqs.stream() + .filter(mcq -> mcq.getId().equals(attempt.getMcqId())) + .findFirst() + .orElse(null)); } private int calculatePoints(List mcqs) { diff --git a/src/test/java/com/quemistry/quiz_ms/controller/QuizControllerTest.java b/src/test/java/com/quemistry/quiz_ms/controller/QuizControllerTest.java index 42b7002..bb40197 100644 --- a/src/test/java/com/quemistry/quiz_ms/controller/QuizControllerTest.java +++ b/src/test/java/com/quemistry/quiz_ms/controller/QuizControllerTest.java @@ -1,5 +1,6 @@ package com.quemistry.quiz_ms.controller; +import static com.quemistry.quiz_ms.fixture.TestFixture.studentContext; import static com.quemistry.quiz_ms.fixture.TestFixture.tutorContext; import static org.mockito.Mockito.*; import static org.mockito.Mockito.doThrow; @@ -16,7 +17,6 @@ import com.quemistry.quiz_ms.exception.NotFoundException; import com.quemistry.quiz_ms.model.QuizStatus; import com.quemistry.quiz_ms.service.QuizService; -import java.util.ArrayList; import java.util.Date; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -24,6 +24,9 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @@ -46,18 +49,13 @@ void setUp() { @Test void createQuiz() throws Exception { - List mcqResponses = new ArrayList<>(); - mcqResponses.add(MCQResponse.builder().id(1L).attemptOption(1).attemptOn(new Date()).build()); - - QuizResponse quizResponse = - QuizResponse.builder() - .id(1L) - .mcqs(mcqResponses) - .pageNumber(0) - .pageSize(1) - .totalPages(1) - .totalRecords(1L) - .build(); + Page mcqResponses = + new PageImpl<>( + List.of(MCQResponse.builder().id(1L).attemptOption(1).attemptOn(new Date()).build()), + PageRequest.of(0, 1), + 1); + + QuizResponse quizResponse = QuizResponse.builder().id(1L).mcqs(mcqResponses).build(); QuizRequest quizRequest = QuizRequest.builder().pageSize(1).totalSize(1L).build(); @@ -80,18 +78,13 @@ void createQuiz() throws Exception { @Test void getQuiz() throws Exception { - List mcqResponses = new ArrayList<>(); - mcqResponses.add(MCQResponse.builder().id(1L).attemptOption(1).attemptOn(new Date()).build()); - - QuizResponse quizResponse = - QuizResponse.builder() - .id(1L) - .mcqs(mcqResponses) - .pageNumber(0) - .pageSize(1) - .totalPages(1) - .totalRecords(1L) - .build(); + Page mcqResponses = + new PageImpl<>( + List.of(MCQResponse.builder().id(1L).attemptOption(1).attemptOn(new Date()).build()), + PageRequest.of(0, 1), + 1); + + QuizResponse quizResponse = QuizResponse.builder().id(1L).mcqs(mcqResponses).build(); when(quizService.getQuiz(1L, tutorContext, 0, 1)).thenReturn(quizResponse); @@ -132,18 +125,13 @@ void getQuizNotFound() throws Exception { @Test void getInProgressQuiz() throws Exception { - List mcqResponses = new ArrayList<>(); - mcqResponses.add(MCQResponse.builder().id(1L).attemptOption(1).attemptOn(new Date()).build()); - - QuizResponse quizResponse = - QuizResponse.builder() - .id(1L) - .mcqs(mcqResponses) - .pageNumber(0) - .pageSize(1) - .totalPages(1) - .totalRecords(1L) - .build(); + Page mcqResponses = + new PageImpl<>( + List.of(MCQResponse.builder().id(1L).attemptOption(1).attemptOn(new Date()).build()), + PageRequest.of(0, 1), + 1); + + QuizResponse quizResponse = QuizResponse.builder().id(1L).mcqs(mcqResponses).build(); when(quizService.getInProgressQuiz(tutorContext, 0, 1)).thenReturn(quizResponse); @@ -166,31 +154,23 @@ void getInProgressQuiz() throws Exception { void getCompletedQuiz() throws Exception { SimpleQuizResponse simpleQuizResponse = SimpleQuizResponse.builder().id(1L).status(QuizStatus.COMPLETED).points(1).build(); - - QuizListResponse quizResponse = - QuizListResponse.builder() - .pageNumber(0) - .pageSize(1) - .totalPages(1) - .totalRecords(1L) - .quizzes(List.of(simpleQuizResponse)) - .build(); - - when(quizService.getCompletedQuiz(tutorContext, 0, 1)).thenReturn(quizResponse); + PageImpl quizResponses = + new PageImpl<>(List.of(simpleQuizResponse), PageRequest.of(0, 1), 1); + when(quizService.getCompletedQuiz(studentContext, 0, 1)).thenReturn(quizResponses); mockMvc .perform( get("/v1/quizzes/me/completed") - .header("x-user-id", tutorContext.getUserId()) - .header("x-user-email", tutorContext.getUserEmail()) - .header("x-user-roles", tutorContext.getUserRoles()) + .header("x-user-id", studentContext.getUserId()) + .header("x-user-email", studentContext.getUserEmail()) + .header("x-user-roles", studentContext.getUserRoles()) .param("pageNumber", "0") .param("pageSize", "1") .contentType(APPLICATION_JSON)) .andExpect(status().isOk()) - .andExpect(content().json(objectMapper.writeValueAsString(quizResponse))); + .andExpect(content().json(objectMapper.writeValueAsString(quizResponses))); - verify(quizService).getCompletedQuiz(tutorContext, 0, 1); + verify(quizService).getCompletedQuiz(studentContext, 0, 1); } @Test diff --git a/src/test/java/com/quemistry/quiz_ms/service/QuizServiceTest.java b/src/test/java/com/quemistry/quiz_ms/service/QuizServiceTest.java index ac8c5f9..5064a36 100644 --- a/src/test/java/com/quemistry/quiz_ms/service/QuizServiceTest.java +++ b/src/test/java/com/quemistry/quiz_ms/service/QuizServiceTest.java @@ -3,14 +3,15 @@ import static com.quemistry.quiz_ms.model.QuizStatus.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.*; import static org.mockito.Mockito.verify; import com.quemistry.quiz_ms.client.QuestionClient; import com.quemistry.quiz_ms.client.model.*; -import com.quemistry.quiz_ms.controller.model.QuizListResponse; import com.quemistry.quiz_ms.controller.model.QuizRequest; import com.quemistry.quiz_ms.controller.model.QuizResponse; +import com.quemistry.quiz_ms.controller.model.SimpleQuizResponse; import com.quemistry.quiz_ms.exception.AttemptAlreadyExistsException; import com.quemistry.quiz_ms.exception.InProgressQuizAlreadyExistsException; import com.quemistry.quiz_ms.exception.NotFoundException; @@ -54,12 +55,12 @@ void createQuizWithFirstPage() { .topics(List.of(1L, 2L)) .skills(List.of(1L, 2L)) .pageSize(1) - .totalSize(2L) + .totalSize(10L) .build(); RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() - .mcqs(List.of(generateMCQDto(1L, "Question 1"))) + .mcqs(List.of(generateMCQDto(1L, "Question 1"), generateMCQDto(2L, "Question 2"))) .totalPages(1) .totalRecords(2L) .build(); @@ -80,49 +81,17 @@ void createQuizWithFirstPage() { QuizResponse response = quizService.createQuiz(testUserContext, quizRequest); - assertEquals(1, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(2, response.getTotalPages()); - assertEquals(2L, response.getTotalRecords()); + assertEquals(1, response.getMcqs().getSize()); + assertEquals(1, response.getMcqs().getContent().size()); + assertEquals(0, response.getMcqs().getNumber()); + assertEquals(2, response.getMcqs().getTotalPages()); + assertEquals(2L, response.getMcqs().getTotalElements()); assertEquals(IN_PROGRESS, response.getStatus()); verify(quizRepository).findOneByStudentIdAndStatus("student1", IN_PROGRESS); verify(questionClient).retrieveMCQs(any(RetrieveMCQRequest.class), any(), any(), any()); - verify(quizRepository, times(2)).save(any(Quiz.class)); - } - - @Test - void createQuizWithTotalPagesAndRecords() { - QuizRequest quizRequest = - QuizRequest.builder() - .topics(List.of(1L, 2L)) - .skills(List.of(1L, 2L)) - .pageSize(1) - .totalSize(2L) - .build(); - - RetrieveMCQResponse retrieveMCQResponse = - RetrieveMCQResponse.builder() - .mcqs(List.of(generateMCQDto(1L, "Question 1"), generateMCQDto(2L, "Question 2"))) - .totalPages(2) - .totalRecords(2L) - .build(); - - when(quizRepository.findOneByStudentIdAndStatus("student1", IN_PROGRESS)) - .thenReturn(Optional.empty()); - when(questionClient.retrieveMCQs(any(RetrieveMCQRequest.class), any(), any(), any())) - .thenReturn(retrieveMCQResponse); - when(quizRepository.save(any(Quiz.class))).thenAnswer(invocation -> invocation.getArgument(0)); - - QuizResponse response = quizService.createQuiz(testUserContext, quizRequest); - - assertEquals(1, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(2, response.getTotalPages()); - assertEquals(2L, response.getTotalRecords()); - assertEquals(IN_PROGRESS, response.getStatus()); + verify(quizRepository, times(1)).save(any(Quiz.class)); + verify(attemptRepository, times(2)).save(any(QuizAttempt.class)); } @Test @@ -146,15 +115,24 @@ void createQuizWithLimitedTotalSize() { .thenReturn(Optional.empty()); when(questionClient.retrieveMCQs(any(RetrieveMCQRequest.class), any(), any(), any())) .thenReturn(retrieveMCQResponse); - when(quizRepository.save(any(Quiz.class))).thenAnswer(invocation -> invocation.getArgument(0)); + when(quizRepository.save(any(Quiz.class))) + .thenAnswer( + invocation -> { + Quiz quiz = invocation.getArgument(0); + if (quiz.getId() == null) { + quiz.setId(1L); // Simulate the generation of an ID + } + return quiz; + }); QuizResponse response = quizService.createQuiz(testUserContext, quizRequest); - assertEquals(1, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(1, response.getTotalPages()); - assertEquals(1L, response.getTotalRecords()); + assertEquals(1, response.getMcqs().getSize()); + assertEquals(1, response.getMcqs().getContent().size()); + assertEquals(0, response.getMcqs().getNumber()); + assertEquals(1, response.getMcqs().getTotalPages()); + assertEquals(1L, response.getMcqs().getTotalElements()); + assertEquals(IN_PROGRESS, response.getStatus()); } @@ -185,64 +163,86 @@ void getQuizByIdAndStudentIdWithQuizNotOwnedByStudent() { @Test void getQuizByIdAndStudentIdWithFirstPage() { - Quiz quiz = Quiz.builder().id(1L).status(IN_PROGRESS).studentId("student1").build(); - quiz.setAttempts(List.of(QuizAttempt.create(quiz, 1L), QuizAttempt.create(quiz, 2L))); + long quizId = 1L; + long mcqId1 = 2L; + long mcqId2 = 3L; + Quiz quiz = Quiz.builder().id(quizId).status(IN_PROGRESS).studentId("student1").build(); RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() - .mcqs(List.of(generateMCQDto(1L, "Question 1"), generateMCQDto(2L, "Question 2"))) + .mcqs( + List.of(generateMCQDto(mcqId1, "Question 1"), generateMCQDto(mcqId2, "Question 2"))) .totalPages(1) .totalRecords(2L) .build(); - when(quizRepository.findOneByIdAndStudentId(1L, "student1")).thenReturn(Optional.of(quiz)); - when(questionClient.retrieveMCQsByIds(any(RetrieveMCQByIdsRequest.class), any(), any(), any())) + when(quizRepository.findOneByIdAndStudentId(quizId, "student1")).thenReturn(Optional.of(quiz)); + when(attemptRepository.findPageByQuizId(quizId, PageRequest.of(0, 10))) + .thenReturn( + new PageImpl<>( + List.of(QuizAttempt.create(quizId, mcqId1), QuizAttempt.create(quizId, mcqId2)), + PageRequest.of(0, 10), + 2)); + when(questionClient.retrieveMCQsByIds( + argThat(request -> request.getIds().containsAll(List.of(mcqId1, mcqId2))), + any(), + any(), + any())) .thenReturn(retrieveMCQResponse); - QuizResponse response = quizService.getQuiz(1L, testUserContext, 0, 1); + QuizResponse response = quizService.getQuiz(quizId, testUserContext, 0, 10); + + assertEquals(quizId, response.getId()); + + assertEquals(10, response.getMcqs().getSize()); + assertEquals(2, response.getMcqs().getContent().size()); + assertEquals(0, response.getMcqs().getNumber()); + assertEquals(1, response.getMcqs().getTotalPages()); + assertEquals(2L, response.getMcqs().getTotalElements()); - assertEquals(1L, response.getId()); - assertEquals(2, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(1, response.getTotalPages()); - assertEquals(2L, response.getTotalRecords()); assertEquals(IN_PROGRESS, response.getStatus()); - assertNull(response.getMcqs().getFirst().getAttemptOption()); - assertNull(response.getMcqs().getFirst().getAttemptOn()); + assertNull(response.getMcqs().getContent().getFirst().getAttemptOption()); + assertNull(response.getMcqs().getContent().getFirst().getAttemptOn()); } @Test void getQuizByIdAndStudentIdReturnCompletedQuizWithCorrectAnswer() { - Quiz quiz = Quiz.builder().id(1L).status(COMPLETED).studentId("student1").build(); - quiz.setAttempts(List.of(QuizAttempt.builder().quiz(quiz).mcqId(1L).optionNo(1).build())); + long quizId = 1L; + long mcqId1 = 2L; + Quiz quiz = Quiz.builder().id(quizId).status(COMPLETED).studentId("student1").build(); RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() - .mcqs(List.of(generateMCQDto(1L, "Question 1"))) + .mcqs(List.of(generateMCQDto(mcqId1, "Question 1"))) .totalPages(1) .totalRecords(1L) .build(); - when(quizRepository.findOneByIdAndStudentId(1L, "student1")).thenReturn(Optional.of(quiz)); - when(questionClient.retrieveMCQsByIds(any(RetrieveMCQByIdsRequest.class), any(), any(), any())) + when(quizRepository.findOneByIdAndStudentId(quizId, "student1")).thenReturn(Optional.of(quiz)); + QuizAttempt attempt = QuizAttempt.create(quizId, mcqId1); + attempt.setOptionNo(1); + when(attemptRepository.findPageByQuizId(quizId, PageRequest.of(0, 10))) + .thenReturn(new PageImpl<>(List.of(attempt), PageRequest.of(0, 10), 1)); + when(questionClient.retrieveMCQsByIds( + argThat(request -> request.getIds().contains(mcqId1)), any(), any(), any())) .thenReturn(retrieveMCQResponse); - QuizResponse response = quizService.getQuiz(1L, testUserContext, 0, 1); + QuizResponse response = quizService.getQuiz(quizId, testUserContext, 0, 10); assertEquals(1L, response.getId()); - assertEquals(1, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(1, response.getTotalPages()); - assertEquals(1L, response.getTotalRecords()); + + assertEquals(10, response.getMcqs().getSize()); + assertEquals(1, response.getMcqs().getContent().size()); + assertEquals(0, response.getMcqs().getNumber()); + assertEquals(1, response.getMcqs().getTotalPages()); + assertEquals(1L, response.getMcqs().getTotalElements()); + assertEquals(COMPLETED, response.getStatus()); - assertEquals(1, response.getMcqs().getFirst().getAttemptOption()); + assertEquals(1, response.getMcqs().getContent().getFirst().getAttemptOption()); assertEquals(1, response.getPoints()); } @Test void getQuizByIdAndStudentIdReturnCompletedQuizWithIncorrectAnswer() { Quiz quiz = Quiz.builder().id(1L).status(COMPLETED).studentId("student1").build(); - quiz.setAttempts(List.of(QuizAttempt.builder().quiz(quiz).mcqId(1L).optionNo(2).build())); RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() .mcqs(List.of(generateMCQDto(1L, "Question 1"))) @@ -251,10 +251,14 @@ void getQuizByIdAndStudentIdReturnCompletedQuizWithIncorrectAnswer() { .build(); when(quizRepository.findOneByIdAndStudentId(1L, "student1")).thenReturn(Optional.of(quiz)); + QuizAttempt attempt = QuizAttempt.create(1L, 1L); + attempt.setOptionNo(2); + when(attemptRepository.findPageByQuizId(1L, PageRequest.of(0, 10))) + .thenReturn(new PageImpl<>(List.of(attempt), PageRequest.of(0, 10), 1)); when(questionClient.retrieveMCQsByIds(any(RetrieveMCQByIdsRequest.class), any(), any(), any())) .thenReturn(retrieveMCQResponse); - QuizResponse response = quizService.getQuiz(1L, testUserContext, 0, 1); + QuizResponse response = quizService.getQuiz(1L, testUserContext, 0, 10); assertEquals(0, response.getPoints()); } @@ -262,7 +266,6 @@ void getQuizByIdAndStudentIdReturnCompletedQuizWithIncorrectAnswer() { @Test void getInProgressQuizWithFirstPage() { Quiz quiz = Quiz.builder().id(1L).status(IN_PROGRESS).studentId("student1").build(); - quiz.setAttempts(List.of(QuizAttempt.create(quiz, 1L), QuizAttempt.create(quiz, 2L))); RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() .mcqs(List.of(generateMCQDto(1L, "Question 1"), generateMCQDto(2L, "Question 2"))) @@ -272,28 +275,35 @@ void getInProgressQuizWithFirstPage() { when(quizRepository.findOneByStudentIdAndStatus("student1", IN_PROGRESS)) .thenReturn(Optional.of(quiz)); + when(attemptRepository.findPageByQuizId(1L, PageRequest.of(0, 10))) + .thenReturn( + new PageImpl<>( + List.of(QuizAttempt.create(1L, 1L), QuizAttempt.create(1L, 2L)), + PageRequest.of(0, 10), + 2)); when(questionClient.retrieveMCQsByIds(any(RetrieveMCQByIdsRequest.class), any(), any(), any())) .thenReturn(retrieveMCQResponse); - QuizResponse response = quizService.getInProgressQuiz(testUserContext, 0, 1); + QuizResponse response = quizService.getInProgressQuiz(testUserContext, 0, 10); assertEquals(1L, response.getId()); - assertEquals(2, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(1, response.getTotalPages()); - assertEquals(2L, response.getTotalRecords()); + + assertEquals(10, response.getMcqs().getSize()); + assertEquals(2, response.getMcqs().getContent().size()); + assertEquals(0, response.getMcqs().getNumber()); + assertEquals(1, response.getMcqs().getTotalPages()); + assertEquals(2L, response.getMcqs().getTotalElements()); + assertEquals(IN_PROGRESS, response.getStatus()); - assertNull(response.getMcqs().getFirst().getAttemptOption()); - assertNull(response.getMcqs().getFirst().getAttemptOn()); + assertNull(response.getMcqs().getContent().getFirst().getAttemptOption()); + assertNull(response.getMcqs().getContent().getFirst().getAttemptOn()); } @Test void getInProgressQuizWithFirstPageWithAttempt() { Date now = new Date(); Quiz quiz = Quiz.builder().id(1L).status(IN_PROGRESS).studentId("student1").build(); - quiz.setAttempts( - List.of(QuizAttempt.builder().quiz(quiz).mcqId(1L).optionNo(1).attemptTime(now).build())); + RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() .mcqs(List.of(generateMCQDto(1L, "Question 1"))) @@ -303,27 +313,32 @@ void getInProgressQuizWithFirstPageWithAttempt() { when(quizRepository.findOneByStudentIdAndStatus("student1", IN_PROGRESS)) .thenReturn(Optional.of(quiz)); + QuizAttempt attempt = QuizAttempt.create(1L, 1L); + attempt.setOptionNo(1); + attempt.setAttemptTime(now); + when(attemptRepository.findPageByQuizId(1L, PageRequest.of(0, 10))) + .thenReturn(new PageImpl<>(List.of(attempt), PageRequest.of(0, 10), 1)); when(questionClient.retrieveMCQsByIds(any(RetrieveMCQByIdsRequest.class), any(), any(), any())) .thenReturn(retrieveMCQResponse); - QuizResponse response = quizService.getInProgressQuiz(testUserContext, 0, 1); + QuizResponse response = quizService.getInProgressQuiz(testUserContext, 0, 10); assertEquals(1L, response.getId()); - assertEquals(1, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(1, response.getTotalPages()); - assertEquals(1L, response.getTotalRecords()); + + assertEquals(10, response.getMcqs().getSize()); + assertEquals(1, response.getMcqs().getContent().size()); + assertEquals(0, response.getMcqs().getNumber()); + assertEquals(1, response.getMcqs().getTotalPages()); + assertEquals(1L, response.getMcqs().getTotalElements()); + assertEquals(IN_PROGRESS, response.getStatus()); - assertEquals(1, response.getMcqs().getFirst().getAttemptOption()); - assertEquals(now, response.getMcqs().getFirst().getAttemptOn()); + assertEquals(1, response.getMcqs().getContent().getFirst().getAttemptOption()); + assertEquals(now, response.getMcqs().getContent().getFirst().getAttemptOn()); } @Test void getInProgressQuizWithFirstPageWithoutAttempt() { - Quiz quiz = - Quiz.builder().id(1L).status(IN_PROGRESS).attempts(List.of()).studentId("student1").build(); - quiz.setAttempts(List.of(QuizAttempt.create(quiz, 1L))); + Quiz quiz = Quiz.builder().id(1L).status(IN_PROGRESS).studentId("student1").build(); RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() .mcqs(List.of(generateMCQDto(1L, "Question 1"))) @@ -333,34 +348,32 @@ void getInProgressQuizWithFirstPageWithoutAttempt() { when(quizRepository.findOneByStudentIdAndStatus("student1", IN_PROGRESS)) .thenReturn(Optional.of(quiz)); + when(attemptRepository.findPageByQuizId(1L, PageRequest.of(0, 10))) + .thenReturn(new PageImpl<>(List.of(QuizAttempt.create(1L, 1L)), PageRequest.of(0, 10), 1)); when(questionClient.retrieveMCQsByIds(any(RetrieveMCQByIdsRequest.class), any(), any(), any())) .thenReturn(retrieveMCQResponse); - QuizResponse response = quizService.getInProgressQuiz(testUserContext, 0, 1); + QuizResponse response = quizService.getInProgressQuiz(testUserContext, 0, 10); assertEquals(1L, response.getId()); - assertEquals(1, response.getMcqs().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(1, response.getTotalPages()); - assertEquals(1L, response.getTotalRecords()); + assertEquals(10, response.getMcqs().getSize()); + assertEquals(1, response.getMcqs().getContent().size()); + assertEquals(0, response.getMcqs().getNumber()); + assertEquals(1, response.getMcqs().getTotalPages()); + assertEquals(1L, response.getMcqs().getTotalElements()); + assertEquals(IN_PROGRESS, response.getStatus()); - assertNull(response.getMcqs().getFirst().getAttemptOption()); - assertNull(response.getMcqs().getFirst().getAttemptOn()); + assertNull(response.getMcqs().getContent().getFirst().getAttemptOption()); + assertNull(response.getMcqs().getContent().getFirst().getAttemptOn()); } @Test void getCompletedQuizWithFirstPage() { - Page quizzes = new PageImpl<>( - List.of( - Quiz.builder() - .id(1L) - .status(COMPLETED) - .attempts(List.of(QuizAttempt.builder().mcqId(1L).optionNo(1).build())) - .studentId("student1") - .build())); + List.of(Quiz.builder().id(1L).status(COMPLETED).studentId("student1").build()), + PageRequest.of(0, 10), + 1); RetrieveMCQResponse retrieveMCQResponse = RetrieveMCQResponse.builder() .mcqs(List.of(generateMCQDto(1L, "Question 1"))) @@ -370,36 +383,37 @@ void getCompletedQuizWithFirstPage() { when(quizRepository.findPageByStudentIdAndStatus("student1", COMPLETED, PageRequest.of(0, 1))) .thenReturn(quizzes); + QuizAttempt attempt = QuizAttempt.create(1L, 1L); + attempt.setOptionNo(1); + when(attemptRepository.findAllByQuizIdIn(argThat(argument -> argument.contains(1L)))) + .thenReturn(List.of(attempt)); when(questionClient.retrieveMCQsByIds(any(RetrieveMCQByIdsRequest.class), any(), any(), any())) .thenReturn(retrieveMCQResponse); - QuizListResponse response = quizService.getCompletedQuiz(testUserContext, 0, 1); + Page response = quizService.getCompletedQuiz(testUserContext, 0, 1); - assertEquals(1, response.getQuizzes().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); + assertEquals(10, response.getSize()); + assertEquals(1, response.getContent().size()); + assertEquals(0, response.getNumber()); assertEquals(1, response.getTotalPages()); - assertEquals(1L, response.getTotalRecords()); - assertEquals(COMPLETED, response.getQuizzes().getFirst().getStatus()); - assertEquals(1, response.getQuizzes().getFirst().getPoints()); + assertEquals(1L, response.getTotalElements()); + assertEquals(COMPLETED, response.getContent().getFirst().getStatus()); + assertEquals(1, response.getContent().getFirst().getPoints()); } @Test void getCompletedQuizWithoutData() { - Page quizzes = new PageImpl<>(List.of()); - RetrieveMCQResponse retrieveMCQResponse = - RetrieveMCQResponse.builder().mcqs(List.of()).totalPages(1).totalRecords(1L).build(); - - when(quizRepository.findPageByStudentIdAndStatus("student1", COMPLETED, PageRequest.of(0, 1))) + Page quizzes = new PageImpl<>(List.of(), PageRequest.of(0, 10), 0); + when(quizRepository.findPageByStudentIdAndStatus("student1", COMPLETED, PageRequest.of(0, 10))) .thenReturn(quizzes); - QuizListResponse response = quizService.getCompletedQuiz(testUserContext, 0, 1); + Page response = quizService.getCompletedQuiz(testUserContext, 0, 10); - assertEquals(0, response.getQuizzes().size()); - assertEquals(0, response.getPageNumber()); - assertEquals(1, response.getPageSize()); - assertEquals(1, response.getTotalPages()); - assertEquals(0L, response.getTotalRecords()); + assertEquals(10, response.getSize()); + assertEquals(0, response.getContent().size()); + assertEquals(0, response.getNumber()); + assertEquals(0, response.getTotalPages()); + assertEquals(0L, response.getTotalElements()); verify(questionClient, never()).retrieveMCQsByIds(any(), any(), any(), any()); } @@ -411,10 +425,10 @@ void updateAttemptSuccess() { String studentId = "student1"; Integer attemptOption = 1; Quiz quiz = Quiz.builder().id(quizId).status(IN_PROGRESS).studentId("student1").build(); - QuizAttempt attempt = - QuizAttempt.builder().optionNo(null).quizId(quizId).quiz(quiz).mcqId(mcqId).build(); + QuizAttempt attempt = QuizAttempt.builder().optionNo(null).quizId(quizId).mcqId(mcqId).build(); when(quizRepository.existsByIdAndStudentId(quizId, studentId)).thenReturn(true); + when(quizRepository.findOneByIdAndStudentId(quizId, studentId)).thenReturn(Optional.of(quiz)); when(attemptRepository.findByQuizIdAndMcqId(quizId, mcqId)).thenReturn(Optional.of(attempt)); quizService.updateAttempt(quizId, mcqId, studentId, attemptOption); @@ -430,10 +444,10 @@ void updateAttemptSuccessWithNotAnsweredQuestion() { String studentId = "student1"; Integer attemptOption = 1; Quiz quiz = Quiz.builder().id(quizId).status(IN_PROGRESS).studentId("student1").build(); - QuizAttempt attempt = - QuizAttempt.builder().optionNo(null).quizId(quizId).quiz(quiz).mcqId(mcqId).build(); + QuizAttempt attempt = QuizAttempt.builder().optionNo(null).quizId(quizId).mcqId(mcqId).build(); when(quizRepository.existsByIdAndStudentId(quizId, studentId)).thenReturn(true); + when(quizRepository.findOneByIdAndStudentId(quizId, studentId)).thenReturn(Optional.of(quiz)); when(attemptRepository.findByQuizIdAndMcqId(quizId, mcqId)).thenReturn(Optional.of(attempt)); when(attemptRepository.existsByQuizIdAndOptionNoIsNull(quizId)).thenReturn(true); @@ -497,10 +511,10 @@ void updateAttemptCompleteQuiz() { String studentId = "student1"; Integer attemptOption = 1; Quiz quiz = Quiz.builder().id(quizId).status(IN_PROGRESS).studentId("student1").build(); - QuizAttempt attempt = - QuizAttempt.builder().optionNo(null).quizId(quizId).quiz(quiz).mcqId(mcqId).build(); + QuizAttempt attempt = QuizAttempt.builder().optionNo(null).quizId(quizId).mcqId(mcqId).build(); when(quizRepository.existsByIdAndStudentId(quizId, studentId)).thenReturn(true); + when(quizRepository.findOneByIdAndStudentId(quizId, studentId)).thenReturn(Optional.of(quiz)); when(attemptRepository.findByQuizIdAndMcqId(quizId, mcqId)).thenReturn(Optional.of(attempt)); when(attemptRepository.existsByQuizIdAndOptionNoIsNull(quizId)).thenReturn(false);