From b377e9e0da94af374d04430613f74213441d92b3 Mon Sep 17 00:00:00 2001 From: Ade Date: Mon, 3 May 2021 15:38:09 +0100 Subject: [PATCH 1/2] fix inconsistencies with api spec and refactor --- .../mathdojo/MathDojoQuestionRepository.java | 3 +- src/main/java/io/mathdojo/Question.java | 5 + .../java/io/mathdojo/QuestionFunction.java | 164 +++++++------- .../java/io/mathdojo/QuestionHandler.java | 4 +- .../java/io/mathdojo/QuestionService.java | 142 ++++++++++++ .../mathdojo/QuestionServiceApplication.java | 13 ++ .../io/mathdojo/QuestionServiceException.java | 19 ++ src/main/java/io/mathdojo/Topic.java | 5 + src/main/java/io/mathdojo/TopicHandler.java | 4 +- .../io/mathdojo/QuestionFunctionTest.java | 130 ----------- .../java/io/mathdojo/QuestionServiceTest.java | 203 ++++++++++++++++++ 11 files changed, 465 insertions(+), 227 deletions(-) create mode 100644 src/main/java/io/mathdojo/QuestionService.java create mode 100644 src/main/java/io/mathdojo/QuestionServiceApplication.java create mode 100644 src/main/java/io/mathdojo/QuestionServiceException.java delete mode 100644 src/test/java/io/mathdojo/QuestionFunctionTest.java create mode 100644 src/test/java/io/mathdojo/QuestionServiceTest.java diff --git a/src/main/java/io/mathdojo/MathDojoQuestionRepository.java b/src/main/java/io/mathdojo/MathDojoQuestionRepository.java index 2ce0732..acf14fa 100644 --- a/src/main/java/io/mathdojo/MathDojoQuestionRepository.java +++ b/src/main/java/io/mathdojo/MathDojoQuestionRepository.java @@ -1,6 +1,5 @@ package io.mathdojo; -import java.util.Collection; import java.util.List; import org.springframework.data.mongodb.repository.MongoRepository; @@ -10,6 +9,8 @@ public interface MathDojoQuestionRepository extends MongoRepository { List findByQuestionTitle(String questionTitle); + + List findByDifficulty(String difficulty); } diff --git a/src/main/java/io/mathdojo/Question.java b/src/main/java/io/mathdojo/Question.java index 456db43..cff57ef 100644 --- a/src/main/java/io/mathdojo/Question.java +++ b/src/main/java/io/mathdojo/Question.java @@ -186,6 +186,11 @@ public boolean equals(Object obj) { return true; } + public boolean isValid() { + //object validation rules to be decided + return true; + } + diff --git a/src/main/java/io/mathdojo/QuestionFunction.java b/src/main/java/io/mathdojo/QuestionFunction.java index 9acaad2..c473501 100644 --- a/src/main/java/io/mathdojo/QuestionFunction.java +++ b/src/main/java/io/mathdojo/QuestionFunction.java @@ -1,142 +1,122 @@ package io.mathdojo; -import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; -import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; -import com.google.common.collect.Iterables; +import com.microsoft.azure.functions.ExecutionContext; -@SpringBootApplication +import reactor.core.publisher.Flux; + +@Configuration public class QuestionFunction { - /** - * This class contains all the functions that can be called in this service. - * Functions are called through RequestHandler classes - */ @Autowired - public MathDojoQuestionRepository repository; - @Autowired - public MathDojoTopicRepository tRepository; - - public static void main(String[] args) throws Exception { - SpringApplication.run(QuestionFunction.class, args); - } + public QuestionService questionService; @Bean - public Function getQuestion() { - return input -> Iterables.getFirst( - repository.findByQuestionTitle(input.getQuestionTitle()).stream() - .filter(i -> i.getDifficulty().equals(input.getDifficulty())).collect(Collectors.toList()), - Question.EMPTY_DATABASE); + public Function, Flux>> getQuestionsByTitleAndDifficulty() { + return questionFluxEntity -> { + return questionFluxEntity.map(question -> { + return questionService.findQuestionsByTitleAndDifficulty(question.getQuestionTitle(), + question.getDifficulty()); + }); + }; } @Bean - public Consumer createQuestion() { - return question -> repository.save(question); + public Function, Flux> createQuestion(ExecutionContext context) { + return questionFluxEntity -> { + return questionFluxEntity.map(question -> { + context.getLogger().info("creating question with title " + question.getQuestionTitle()); + return questionService.createQuestion(question); + }); + }; } @Bean - public Function getQuestionById() { - return question -> repository.findById(question.getId()).isPresent() - ? repository.findById(question.getId()).get() - : Question.EMPTY_DATABASE; + public Function, Flux> getQuestionById(ExecutionContext context) { + return questionFluxEntity -> { + return questionFluxEntity.map(questionId -> { + context.getLogger().info("retrieving question with id " + questionId); + return questionService.getQuestionById(questionId); + }); + }; + } @Bean - public Consumer updateQuestion() { - return new Consumer() { - - @Override - public void accept(Question question) { - Question oldQuestion = repository.findById(question.getId()).isPresent() - ? repository.findById(question.getId()).get() - : null; - Question newQuestion = new Question(question.getId(), - question.getQuestionTitle() != null ? question.getQuestionTitle() - : oldQuestion.getQuestionTitle(), - question.getQuestionBody() != null ? question.getQuestionBody() : oldQuestion.getQuestionBody(), - question.getSampleAnswer() != null ? question.getSampleAnswer() : oldQuestion.getSampleAnswer(), - question.getSuccessRate() != null ? question.getSuccessRate() : oldQuestion.getSuccessRate(), - question.getDifficulty() != null ? question.getDifficulty() : oldQuestion.getDifficulty(), - question.getHints() != null ? question.getHints() : oldQuestion.getHints(), - question.getParentTopicTitle() != null ? question.getParentTopicTitle() - : oldQuestion.getParentTopicTitle(), - question.getQuestionAnswerOptions() != null ? question.getQuestionAnswerOptions() - : oldQuestion.getQuestionAnswerOptions(), - question.getAnswer() != null ? question.getAnswer() : oldQuestion.getAnswer()); - ; - repository.save(newQuestion); - } - + public Function, Flux> updateQuestion(ExecutionContext context) { + return questionFluxEntity -> { + return questionFluxEntity.map(question -> { + context.getLogger().info("updating question with id " + question.getId()); + return questionService.updateQuestionById(question); + }); }; } @Bean - public Consumer deleteQuestion() { - return question -> repository.deleteById(question.getId()); + public Consumer deleteQuestionById(ExecutionContext context) { + return deletionRequest -> questionService.deleteQuestionById(deletionRequest.getId()); } @Bean - public Function getTopic() { - return input -> Iterables.getFirst( - tRepository.findByTopicTitle(input.getTopicTitle()).stream().collect(Collectors.toList()), - Topic.EMPTY_DATABASE); + public Function, Flux>> getTopicsByTitle() { + return topicFluxEntity -> { + return topicFluxEntity.map(topic -> { + return questionService.findTopicsByTitle(topic.getTopicTitle()); + }); + }; } @Bean - public Consumer createTopic() { - return topic -> tRepository.save(topic); + public Function, Flux> createTopic(ExecutionContext context) { + return topicFluxEntity -> { + return topicFluxEntity.map(topic -> { + context.getLogger().info("creating topic with title " + topic.getTopicTitle()); + return questionService.createTopic(topic); + }); + }; } @Bean - public Function getTopicById() { - return topic -> tRepository.findById(topic.getId()).isPresent() ? tRepository.findById(topic.getId()).get() - : Topic.EMPTY_DATABASE; + public Function, Flux> getTopicById(ExecutionContext context) { + return topicFluxEntity -> { + return topicFluxEntity.map(topicId -> { + context.getLogger().info("retrieving topic with id " + topicId); + return questionService.getTopicById(topicId); + }); + }; } @Bean - public Consumer updateTopic() { - - return new Consumer() { - - @Override - public void accept(Topic topic) { - Topic oldTopic = tRepository.findById(topic.getId()).isPresent() - ? tRepository.findById(topic.getId()).get() - : null; - Topic newTopic = new Topic(topic.getId(), - topic.getTopicTitle() != null ? topic.getTopicTitle() : oldTopic.getTopicTitle(), - topic.getName() != null ? topic.getName() : oldTopic.getName(), - topic.getQuestions() != null ? topic.getQuestions() : oldTopic.getQuestions()); - tRepository.save(newTopic); - } - + public Function, Flux> updateTopic(ExecutionContext context) { + return topicFluxEntity -> { + return topicFluxEntity.map(topic -> { + context.getLogger().info("retrieving topic with id " + topic); + return questionService.updateTopicById(topic); + }); }; } @Bean - public Consumer deleteTopic() { - return topic -> tRepository.deleteById(topic.getId()); + public Consumer deleteTopicById(ExecutionContext context) { + return deletionRequest -> questionService.deleteTopicById(deletionRequest.getId()); } @Bean - public Function> getQuestions() { - - return new Function>() { - @Override - public List apply(Topic t) { - List x = new ArrayList<>(); - repository.findAllById(tRepository.findById(t.getId()).get().getQuestions()).forEach(x::add); - return x; - } + public Function, Flux>> getQuestions(ExecutionContext context) { + + return topicFluxEntity -> { + return topicFluxEntity.map(topic -> { + context.getLogger().info("retrieving questions of topic " + topic.getTopicTitle()); + return questionService.getAllQuestionsInTopic(topic.getId()); + }); }; - } + } } \ No newline at end of file diff --git a/src/main/java/io/mathdojo/QuestionHandler.java b/src/main/java/io/mathdojo/QuestionHandler.java index 9a78583..9ad3cd8 100644 --- a/src/main/java/io/mathdojo/QuestionHandler.java +++ b/src/main/java/io/mathdojo/QuestionHandler.java @@ -22,7 +22,7 @@ public class QuestionHandler extends AzureSpringBootRequestHandler { - @FunctionName("getQuestion") + @FunctionName("getQuestionsByTitleAndDifficulty") public Question executeGet(@HttpTrigger(name = "request", methods = { HttpMethod.GET }, authLevel = AuthorizationLevel.ANONYMOUS, route = "question") HttpRequestMessage> request, ExecutionContext context) { @@ -61,7 +61,7 @@ public Question executeUpdate( return handleRequest(request.getBody().get(), context); } - @FunctionName("deleteQuestion") + @FunctionName("deleteQuestionById") public Question executeDelete(@HttpTrigger(name = "request", methods = { HttpMethod.DELETE }, authLevel = AuthorizationLevel.ANONYMOUS, route = "questions/{questionId}") HttpRequestMessage> request, ExecutionContext context, @BindingName("questionId") String questionId) { diff --git a/src/main/java/io/mathdojo/QuestionService.java b/src/main/java/io/mathdojo/QuestionService.java new file mode 100644 index 0000000..0f0f55f --- /dev/null +++ b/src/main/java/io/mathdojo/QuestionService.java @@ -0,0 +1,142 @@ +package io.mathdojo; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; + +public class QuestionService { + + + @Autowired + private MathDojoQuestionRepository qRepo; + + @Autowired + private MathDojoTopicRepository tRepo; + + public QuestionService() { + } + + public Question getQuestionById(String id) throws QuestionServiceException { + if (!questionExists(id)) { + throw new QuestionServiceException(QuestionServiceException.NOT_FOUND); + } + return qRepo.findById(id).get(); + } + + public Topic getTopicById(String id) throws QuestionServiceException { + if (!topicExists(id)) { + throw new QuestionServiceException(QuestionServiceException.NOT_FOUND); + } + return tRepo.findById(id).get(); + } + + public Question updateQuestionById(Question question) throws QuestionServiceException { + if (!questionExists(question.getId())) { + throw new QuestionServiceException(QuestionServiceException.NOT_FOUND); + } + Question oldQuestion = qRepo.findById(question.getId()).get(); + + Question newQuestion = new Question(question.getId(), + question.getQuestionTitle() != null ? question.getQuestionTitle() : oldQuestion.getQuestionTitle(), + question.getQuestionBody() != null ? question.getQuestionBody() : oldQuestion.getQuestionBody(), + question.getSampleAnswer() != null ? question.getSampleAnswer() : oldQuestion.getSampleAnswer(), + question.getSuccessRate() != null ? question.getSuccessRate() : oldQuestion.getSuccessRate(), + question.getDifficulty() != null ? question.getDifficulty() : oldQuestion.getDifficulty(), + question.getHints() != null ? question.getHints() : oldQuestion.getHints(), + question.getParentTopicTitle() != null ? question.getParentTopicTitle() + : oldQuestion.getParentTopicTitle(), + question.getQuestionAnswerOptions() != null ? question.getQuestionAnswerOptions() + : oldQuestion.getQuestionAnswerOptions(), + question.getAnswer() != null ? question.getAnswer() : oldQuestion.getAnswer()); + + return qRepo.save(newQuestion); + + } + + public Topic updateTopicById(Topic topic) throws QuestionServiceException { + if (!topicExists(topic.getId())) { + throw new QuestionServiceException(QuestionServiceException.NOT_FOUND); + } + Topic oldTopic = tRepo.findById(topic.getId()).get(); + + Topic newTopic = new Topic(topic.getId(), + topic.getTopicTitle() != null ? topic.getTopicTitle() : oldTopic.getTopicTitle(), + topic.getName() != null ? topic.getName() : oldTopic.getName(), + topic.getQuestions() != null ? topic.getQuestions() : oldTopic.getQuestions()); + return tRepo.save(newTopic); + + } + + public void deleteQuestionById(String id) throws QuestionServiceException { + if (!questionExists(id)) { + throw new QuestionServiceException(QuestionServiceException.NOT_FOUND); + } + qRepo.deleteById(id); + } + + public void deleteTopicById(String id) throws QuestionServiceException { + if (!topicExists(id)) { + throw new QuestionServiceException(QuestionServiceException.NOT_FOUND); + } + tRepo.deleteById(id); + } + + public Question createQuestion(Question question) throws QuestionServiceException { + if (questionExists(question.getId()) || !question.isValid()) { + throw new QuestionServiceException(QuestionServiceException.BAD_REQUEST); + } + return qRepo.save(question); + } + + public Topic createTopic(Topic topic) throws QuestionServiceException { + if (topicExists(topic.getId()) || !topic.isValid()) { + throw new QuestionServiceException(QuestionServiceException.BAD_REQUEST); + } + return tRepo.save(topic); + } + + public List findQuestionsByTitle(String title) { + + return qRepo.findByQuestionTitle(title); + } + + public List getAllQuestionsInTopic(String id) throws QuestionServiceException { + if (!topicExists(id)) { + throw new QuestionServiceException(QuestionServiceException.NOT_FOUND); + } + List retVal = new ArrayList<>(); + qRepo.findAllById(tRepo.findById(id).get().getQuestions()).forEach(retVal::add); + return retVal; + } + + public List findTopicsByTitle(String title) { + + return tRepo.findByTopicTitle(title); + } + + public List findQuestionsByDifficulty(String difficulty) { + + return qRepo.findByQuestionTitle(difficulty); + } + + private boolean questionExists(String id) { + + return qRepo.existsById(id); + } + + private boolean topicExists(String id) { + + return tRepo.existsById(id); + } + + public List findQuestionsByTitleAndDifficulty(String questionTitle, String difficulty) { + Set retVal = new HashSet<>(); + retVal.addAll(findQuestionsByDifficulty(difficulty)); + retVal.addAll(findQuestionsByTitle(questionTitle)); + return new ArrayList<>(retVal); + } + +} diff --git a/src/main/java/io/mathdojo/QuestionServiceApplication.java b/src/main/java/io/mathdojo/QuestionServiceApplication.java new file mode 100644 index 0000000..926407f --- /dev/null +++ b/src/main/java/io/mathdojo/QuestionServiceApplication.java @@ -0,0 +1,13 @@ +package io.mathdojo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class QuestionServiceApplication { + + public static void main(String[] args) throws Exception { + SpringApplication.run(QuestionFunction.class, args); + } + +} diff --git a/src/main/java/io/mathdojo/QuestionServiceException.java b/src/main/java/io/mathdojo/QuestionServiceException.java new file mode 100644 index 0000000..e301e6d --- /dev/null +++ b/src/main/java/io/mathdojo/QuestionServiceException.java @@ -0,0 +1,19 @@ +package io.mathdojo; + +public class QuestionServiceException extends RuntimeException { + + /** + * Exception that represents some error in the operations within the Question + * Service. + */ + + public QuestionServiceException(String message) { + super(message); + } + + private static final long serialVersionUID = -4590570509941979310L; + public static String NOT_FOUND = "Question/Topic not found"; + + public static String BAD_REQUEST = "Bad request"; + +} diff --git a/src/main/java/io/mathdojo/Topic.java b/src/main/java/io/mathdojo/Topic.java index 4cac1cc..658522b 100644 --- a/src/main/java/io/mathdojo/Topic.java +++ b/src/main/java/io/mathdojo/Topic.java @@ -103,4 +103,9 @@ public boolean equals(Object obj) { return true; } + public boolean isValid() { + // object validation rules to be decided + return true; + } + } diff --git a/src/main/java/io/mathdojo/TopicHandler.java b/src/main/java/io/mathdojo/TopicHandler.java index e21f179..ac7e6e2 100644 --- a/src/main/java/io/mathdojo/TopicHandler.java +++ b/src/main/java/io/mathdojo/TopicHandler.java @@ -19,7 +19,7 @@ */ public class TopicHandler extends AzureSpringBootRequestHandler { - @FunctionName("getTopic") + @FunctionName("getTopicsByTitle") public Topic executeGet(@HttpTrigger(name = "request", methods = { HttpMethod.GET }, authLevel = AuthorizationLevel.ANONYMOUS, route = "topics") HttpRequestMessage> request, ExecutionContext context) { @@ -57,7 +57,7 @@ public Topic executeUpdate( return handleRequest(request.getBody().get(), context); } - @FunctionName("deleteTopic") + @FunctionName("deleteTopicById") public Topic executeDelete(@HttpTrigger(name = "request", methods = { HttpMethod.DELETE }, authLevel = AuthorizationLevel.ANONYMOUS, route = "topics/{topicId}") HttpRequestMessage> request, ExecutionContext context, @BindingName("topicId") String topicId) { diff --git a/src/test/java/io/mathdojo/QuestionFunctionTest.java b/src/test/java/io/mathdojo/QuestionFunctionTest.java deleted file mode 100644 index 6ac55b3..0000000 --- a/src/test/java/io/mathdojo/QuestionFunctionTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package io.mathdojo; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.logging.Logger; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.cloud.function.adapter.azure.AzureSpringBootRequestHandler; - -import com.microsoft.azure.functions.ExecutionContext; - -public class QuestionFunctionTest { - - private Question question; - private QuestionFunction qf = new QuestionFunction(); - private MathDojoQuestionRepository repo = mock(MathDojoQuestionRepository.class); - private MathDojoTopicRepository trepo = mock(MathDojoTopicRepository.class); - private Topic topic = new Topic(); - Map headers; - Map queryParams; - - @Before - public void setUp() { - question = new Question(); - question.setQuestionTitle("test"); - question.setDifficulty("easy"); - question.setId("test"); - qf.repository = repo; - qf.tRepository = trepo; - List questionList = new ArrayList(); - questionList.add(question); - when(repo.findByQuestionTitle("test")).thenReturn(questionList); - when(repo.findById("test")).thenReturn(Optional.of(question)); - when(repo.findAllById(new ArrayList(Arrays.asList("test")))).thenReturn(questionList); - topic.setId("test"); - topic.setName("test"); - topic.setTitle("test"); - topic.setQuestions(new ArrayList(Arrays.asList("test"))); - List topicList = new ArrayList(); - topicList.add(topic); - when(trepo.findByTopicTitle("test")).thenReturn(topicList); - when(trepo.findById("test")).thenReturn(Optional.of(topic)); - headers = new HashMap<>(); - queryParams = new HashMap<>(); - - } - - @Test - public void testQuestionAndTopicFunctions() { - Question getQuestionResult = qf.getQuestion().apply(question); - assertEquals(getQuestionResult, question); - qf.updateQuestion().accept(question); - verify(repo, times(1)).save(question); - Question getQuestionByIdResult = qf.getQuestionById().apply(question); - assertEquals(getQuestionByIdResult, question); - qf.deleteQuestion().accept(question); - verify(repo, times(1)).deleteById("test"); - Topic getTopicResult = qf.getTopic().apply(topic); - assertEquals(getTopicResult, topic); - qf.updateTopic().accept(topic); - verify(trepo, times(1)).save(topic); - Topic getTopicByIdResult = qf.getTopicById().apply(topic); - assertEquals(getTopicByIdResult, topic); - qf.deleteTopic().accept(topic); - verify(trepo, times(1)).deleteById("test"); - assertEquals(qf.getQuestions().apply(topic).get(0), question); - - } - - @Ignore - @Test - public void testQuestionHandler() throws URISyntaxException { - AzureSpringBootRequestHandler handler = new AzureSpringBootRequestHandler<>( - QuestionFunction.class); - Question getQuestionResult = handler.handleRequest(question, getExecutionContext("getQuestion")); - Question getQuestionByIdResult = handler.handleRequest(question, getExecutionContext("getQuestionById")); - handler.close(); - assertEquals(getQuestionResult, Question.EMPTY_DATABASE); - assertEquals(getQuestionByIdResult, Question.EMPTY_DATABASE); - - } - - @Ignore - @Test - public void testTopicHandler() { - AzureSpringBootRequestHandler handler = new AzureSpringBootRequestHandler<>( - QuestionFunction.class); - Topic getTopicResult = handler.handleRequest(topic, getExecutionContext("getTopic")); - Topic getTopicByIdResult = handler.handleRequest(topic, getExecutionContext("getTopic")); - - handler.close(); - assertEquals(getTopicResult, Topic.EMPTY_DATABASE); - assertEquals(getTopicByIdResult, Topic.EMPTY_DATABASE); - } - - private ExecutionContext getExecutionContext(String function) { - - return new ExecutionContext() { - - @Override - public Logger getLogger() { - return Logger.getAnonymousLogger(); - } - - @Override - public String getInvocationId() { - return function; - } - - @Override - public String getFunctionName() { - return function; - } - }; - } - -} diff --git a/src/test/java/io/mathdojo/QuestionServiceTest.java b/src/test/java/io/mathdojo/QuestionServiceTest.java new file mode 100644 index 0000000..77f4344 --- /dev/null +++ b/src/test/java/io/mathdojo/QuestionServiceTest.java @@ -0,0 +1,203 @@ +package io.mathdojo; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; +import org.mockito.stubbing.OngoingStubbing; + +@ExtendWith(MockitoExtension.class) +public class QuestionServiceTest { + private static final String PRECONDITIONED_KNOWN_QUESTION = "aKnownQuestion"; + private static final String PRECONDITIONED_KNOWN_TOPIC = "aKnownTopic"; + + @Mock + private MathDojoQuestionRepository qRepo; + @Mock + private MathDojoTopicRepository tRepo; + @InjectMocks + private QuestionService questionService; + + @SuppressWarnings("unchecked") + @BeforeEach + public void setUp() { + Question knownQuestion = new Question(PRECONDITIONED_KNOWN_QUESTION, PRECONDITIONED_KNOWN_QUESTION, null, null, + null, "Easy", null, null, null, null); + Iterable ite = Arrays.asList(knownQuestion); + Topic knownTopic = new Topic(PRECONDITIONED_KNOWN_TOPIC, PRECONDITIONED_KNOWN_TOPIC, PRECONDITIONED_KNOWN_TOPIC, + new ArrayList(Arrays.asList(PRECONDITIONED_KNOWN_QUESTION))); + Mockito.lenient().when(qRepo.save(Mockito.any(Question.class))).thenAnswer(new Answer() { + public Question answer(InvocationOnMock invocation) { + return (Question) invocation.getArguments()[0]; + } + }); + Mockito.lenient().when(tRepo.save(Mockito.any(Topic.class))).thenAnswer(new Answer() { + public Topic answer(InvocationOnMock invocation) { + return (Topic) invocation.getArguments()[0]; + } + }); + + Mockito.lenient().when(qRepo.existsById(PRECONDITIONED_KNOWN_QUESTION)).thenReturn(true); + Mockito.lenient().when(tRepo.existsById(PRECONDITIONED_KNOWN_TOPIC)).thenReturn(true); + Mockito.lenient().when(tRepo.findByTopicTitle(PRECONDITIONED_KNOWN_TOPIC)) + .thenReturn(Arrays.asList(knownTopic)); + Mockito.lenient().when(qRepo.findByQuestionTitle(PRECONDITIONED_KNOWN_QUESTION)) + .thenReturn(Arrays.asList(knownQuestion)); + Mockito.lenient().when(qRepo.findByDifficulty("Easy")).thenReturn(Arrays.asList(knownQuestion)); + Mockito.lenient().when(qRepo.findById(PRECONDITIONED_KNOWN_QUESTION)).thenReturn(Optional.of(knownQuestion)); + Mockito.lenient().when(tRepo.findById(PRECONDITIONED_KNOWN_TOPIC)) + .thenReturn(Optional.of(new Topic(PRECONDITIONED_KNOWN_TOPIC, PRECONDITIONED_KNOWN_TOPIC, + PRECONDITIONED_KNOWN_TOPIC, Arrays.asList(PRECONDITIONED_KNOWN_QUESTION)))); + + } + + @Test + public void testGetQuestionById() { + Question question = questionService.getQuestionById(PRECONDITIONED_KNOWN_QUESTION); + assertEquals(question.getId(), PRECONDITIONED_KNOWN_QUESTION); + + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.getQuestionById(null); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.NOT_FOUND, exceptionMessage); + + } + + @Test + public void testGetTopicById() { + Topic topic = questionService.getTopicById(PRECONDITIONED_KNOWN_TOPIC); + assertEquals(topic.getId(), PRECONDITIONED_KNOWN_TOPIC); + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.getTopicById(null); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.NOT_FOUND, exceptionMessage); + } + + @Test + public void testUpdateQuestion() { + Question question = questionService.getQuestionById(PRECONDITIONED_KNOWN_QUESTION); + question.setAnswer("testAnswer"); + Question updated = questionService.updateQuestionById(question); + assertEquals(updated.getAnswer(), "testAnswer"); + + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.updateQuestionById(new Question()); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.NOT_FOUND, exceptionMessage); + + } + + @Test + public void testUpdateTopic() { + Topic topic = questionService.getTopicById(PRECONDITIONED_KNOWN_TOPIC); + topic.setName("testName"); + Topic updated = questionService.updateTopicById(topic); + assertEquals(updated.getName(), "testName"); + + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.updateTopicById(new Topic()); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.NOT_FOUND, exceptionMessage); + + } + + @Test + public void testDeleteQuestionById() { + + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.deleteQuestionById(null); + ; + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.NOT_FOUND, exceptionMessage); + + } + + @Test + public void testDeleteTopicById() { + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.deleteTopicById(null); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.NOT_FOUND, exceptionMessage); + + } + + @Test + public void testCreateQuestion() { + Question question = questionService.getQuestionById(PRECONDITIONED_KNOWN_QUESTION); + + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.createQuestion(question); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.BAD_REQUEST, exceptionMessage); + + } + + @Test + public void testCreateTopic() { + Topic topic = questionService.getTopicById(PRECONDITIONED_KNOWN_TOPIC); + + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.createTopic(topic); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.BAD_REQUEST, exceptionMessage); + } + + @Test + public void testGetAllQuestionsInTopic() { + + RuntimeException exception = assertThrows(QuestionServiceException.class, () -> { + questionService.getAllQuestionsInTopic(null); + }); + + String exceptionMessage = exception.getMessage(); + assertEquals(QuestionServiceException.NOT_FOUND, exceptionMessage); + } + + @Test + public void testGetTopicsByTitle() { + + List topics = questionService.findTopicsByTitle(PRECONDITIONED_KNOWN_TOPIC); + assertEquals(topics.get(0).getId(), PRECONDITIONED_KNOWN_TOPIC); + + } + + @Test + public void testGetQuestionsByTitleAndDifficulty() { + + List questions = questionService.findQuestionsByTitleAndDifficulty(PRECONDITIONED_KNOWN_QUESTION, + "Easy"); + assertEquals(questions.size(), 1); + assertEquals(questions.get(0).getId(), PRECONDITIONED_KNOWN_QUESTION); + + } +} From 632b937db614fca4f61b71c9374dca60f5c0427c Mon Sep 17 00:00:00 2001 From: Ade Date: Mon, 3 May 2021 15:41:45 +0100 Subject: [PATCH 2/2] Fix /question routes to /questions --- src/main/java/io/mathdojo/QuestionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/mathdojo/QuestionHandler.java b/src/main/java/io/mathdojo/QuestionHandler.java index 9ad3cd8..370bae0 100644 --- a/src/main/java/io/mathdojo/QuestionHandler.java +++ b/src/main/java/io/mathdojo/QuestionHandler.java @@ -24,7 +24,7 @@ public class QuestionHandler extends AzureSpringBootRequestHandler> request, + HttpMethod.GET }, authLevel = AuthorizationLevel.ANONYMOUS, route = "questions") HttpRequestMessage> request, ExecutionContext context) { context.getLogger().info("Retrieving question");