diff --git a/backend/Dockerfile b/backend/Dockerfile
index fd634e1..14463aa 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -22,11 +22,8 @@ CMD ["tail","-f","/dev/null"]
#---Building
FROM base AS build
COPY . .
-RUN mvn clean package -DskipTests
-
-#--Testing
-FROM build AS testing
-RUN mvn clean test
+RUN mvn clean package
+# Add -DskipTests for slightly faster build, but no testing
#---Production
# Pulled again to get rid of maven, to decrease the size
diff --git a/backend/pom.xml b/backend/pom.xml
index ac725c2..a1fe9a5 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -32,10 +32,10 @@
3.1.8
-
+
org.springframework.boot
spring-boot-starter-web
@@ -47,11 +47,11 @@
runtime
true
-
+
org.springframework.boot
spring-boot-starter-test
diff --git a/backend/src/main/java/com/ninjaws/quiz/models/Question.java b/backend/src/main/java/com/ninjaws/quiz/models/Question.java
index 36ee786..6c0a32d 100644
--- a/backend/src/main/java/com/ninjaws/quiz/models/Question.java
+++ b/backend/src/main/java/com/ninjaws/quiz/models/Question.java
@@ -7,10 +7,20 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.persistence.*;
import lombok.Getter;
+import lombok.Setter;
+@Entity
+@Table(name = "question")
@Getter
+@Setter
public class Question {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
private String type;
private String difficulty;
private String category;
diff --git a/backend/src/main/java/com/ninjaws/quiz/repositories/QuestionRepository.java b/backend/src/main/java/com/ninjaws/quiz/repositories/QuestionRepository.java
new file mode 100644
index 0000000..31e331a
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/repositories/QuestionRepository.java
@@ -0,0 +1,8 @@
+package com.ninjaws.quiz.repositories;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.ninjaws.quiz.models.Question;
+
+public interface QuestionRepository extends JpaRepository {
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/DataService.java b/backend/src/main/java/com/ninjaws/quiz/services/DataService.java
new file mode 100644
index 0000000..ceefcd0
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/services/DataService.java
@@ -0,0 +1,27 @@
+package com.ninjaws.quiz.services;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.ninjaws.quiz.models.Question;
+import com.ninjaws.quiz.repositories.QuestionRepository;
+
+@Service
+public class DataService {
+ @Autowired
+ private QuestionRepository questionRepository;
+
+ public List getAllQuestions() {
+ return questionRepository.findAll();
+ }
+
+ public Question saveQuestion(Question question) {
+ return questionRepository.save(question);
+ }
+
+ public List saveQuestions(List questions) {
+ return questionRepository.saveAll(questions);
+ }
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java b/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java
index af391f0..07abae9 100644
--- a/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java
+++ b/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java
@@ -11,6 +11,8 @@ public class ResponseHandlingService {
@Autowired
private CacheService cacheService;
+ @Autowired
+ private DataService dataService;
/**
* If there is no sessionId, then this is a request from the scheduler
@@ -62,6 +64,7 @@ public class ResponseHandlingService {
switch (response.getResponseCode()) {
case 0:
// TODO: Store in DB
+ dataService.saveQuestions(response.getResults());
break;
case 4:
// Signal DataService that we have extracted all the data. Stop gathering, switch to caching-mode
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/SchedulerService.java b/backend/src/main/java/com/ninjaws/quiz/services/SchedulerService.java
index a57f3c9..41b7dc4 100644
--- a/backend/src/main/java/com/ninjaws/quiz/services/SchedulerService.java
+++ b/backend/src/main/java/com/ninjaws/quiz/services/SchedulerService.java
@@ -27,6 +27,8 @@ public class SchedulerService {
Request request = queueService.popFromQueue();
if (request != null) {
apiService.handleRequest(request);
+ } else {
+ apiService.collectBulk();
}
}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/StorageService.java b/backend/src/main/java/com/ninjaws/quiz/services/StorageService.java
deleted file mode 100644
index d670143..0000000
--- a/backend/src/main/java/com/ninjaws/quiz/services/StorageService.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.ninjaws.quiz.services;
-
-public class StorageService {
-
-}
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index 8d23e20..5fa94c6 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -1,2 +1,12 @@
spring.application.name=quiz
-server.port=9090
\ No newline at end of file
+server.port=9090
+
+# H2 Database configuration
+spring.h2.console.enabled=true
+spring.datasource.url=jdbc:h2:mem:testdb
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/backend/src/test/java/com/ninjaws/quiz/repositories/QuestRepositoryTest.java b/backend/src/test/java/com/ninjaws/quiz/repositories/QuestRepositoryTest.java
new file mode 100644
index 0000000..a11b441
--- /dev/null
+++ b/backend/src/test/java/com/ninjaws/quiz/repositories/QuestRepositoryTest.java
@@ -0,0 +1,91 @@
+package com.ninjaws.quiz.repositories;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.annotation.Rollback;
+
+import com.ninjaws.quiz.models.Question;
+
+@DataJpaTest
+public class QuestRepositoryTest {
+ @Autowired
+ private QuestionRepository questionRepository;
+
+ private Question question;
+
+ @BeforeEach
+ public void setUp() {
+ question = new Question();
+ question.setType("multiple choice");
+ question.setDifficulty("easy");
+ question.setCategory("general knowledge");
+ question.setQuestion("What is the capital of France?");
+ question.setCorrectAnswer("Paris");
+ question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+ }
+
+ @Test
+ @Rollback(false)
+ public void testSaveQuestion() {
+ Question savedQuestion = questionRepository.save(question);
+ assertThat(savedQuestion).isNotNull();
+ assertThat(savedQuestion.getId()).isGreaterThan(1);
+ }
+
+ @Test
+ public void testFindQuestionById() {
+ questionRepository.save(question);
+ Optional foundQuestion = questionRepository.findById(question.getId());
+ assertThat(foundQuestion).isPresent();
+ assertThat(foundQuestion.get().getQuestion()).isEqualTo(question.getQuestion());
+ }
+
+ @Test
+ public void testFindAllQuestions() {
+ questionRepository.save(question);
+ List questions = questionRepository.findAll();
+ assertThat(questions).isNotEmpty();
+ }
+
+ @Test
+ public void testDeleteQuestion() {
+ questionRepository.save(question);
+ Long id = question.getId();
+ questionRepository.deleteById(id);
+ Optional deletedQuestion = questionRepository.findById(id);
+ assertThat(deletedQuestion).isNotPresent();
+ }
+
+ @Test
+ @Rollback(false)
+ public void testSaveQuestions() {
+ Question question1 = new Question();
+ question1.setType("multiple choice");
+ question1.setDifficulty("easy");
+ question1.setCategory("general knowledge");
+ question1.setQuestion("What is the capital of France?");
+ question1.setCorrectAnswer("Paris");
+ question1.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+
+ Question question2 = new Question();
+ question2.setType("multiple choice");
+ question2.setDifficulty("medium");
+ question2.setCategory("science");
+ question2.setQuestion("What is the chemical symbol for water?");
+ question2.setCorrectAnswer("H2O");
+ question2.setIncorrectAnswers(Arrays.asList("CO2", "O2", "NaCl"));
+
+ List savedQuestions = questionRepository.saveAll(Arrays.asList(question1, question2));
+
+ assertThat(savedQuestions).hasSize(2);
+ assertThat(savedQuestions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
+ assertThat(savedQuestions.get(1).getQuestion()).isEqualTo("What is the chemical symbol for water?");
+ }
+}
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/CacheServiceTest.java b/backend/src/test/java/com/ninjaws/quiz/services/CacheServiceTest.java
new file mode 100644
index 0000000..63570e8
--- /dev/null
+++ b/backend/src/test/java/com/ninjaws/quiz/services/CacheServiceTest.java
@@ -0,0 +1,59 @@
+package com.ninjaws.quiz.services;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.ninjaws.quiz.models.Session;
+
+public class CacheServiceTest {
+
+ private CacheService cacheService;
+
+ @BeforeEach
+ public void setUp() {
+ cacheService = new CacheService();
+ }
+
+ @Test
+ public void testAddToCache() {
+ String key = "session1";
+ Session session = new Session();
+
+ cacheService.addToCache(key, session);
+
+ assertNotNull(cacheService.getFromCache(key));
+ assertEquals(session, cacheService.getFromCache(key));
+ }
+
+ @Test
+ public void testGetFromCache() {
+ String key = "session1";
+ Session session = new Session();
+
+ cacheService.addToCache(key, session);
+
+ Session retrievedSession = cacheService.getFromCache(key);
+ assertNotNull(retrievedSession);
+ assertEquals(session, retrievedSession);
+ }
+
+ @Test
+ public void testRemoveFromCache() {
+ String key = "session1";
+ Session session = new Session();
+
+ cacheService.addToCache(key, session);
+ cacheService.removeFromCache(key);
+
+ assertNull(cacheService.getFromCache(key));
+ }
+
+ @Test
+ public void testGetFromCacheWithNonExistentKey() {
+ assertNull(cacheService.getFromCache("nonExistentKey"));
+ }
+}
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.java b/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.java
new file mode 100644
index 0000000..8c0f904
--- /dev/null
+++ b/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.java
@@ -0,0 +1,58 @@
+package com.ninjaws.quiz.services;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ninjaws.quiz.models.ApiResponse;
+import com.ninjaws.quiz.models.Question;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+public class CleanerServiceTest {
+
+ @InjectMocks
+ private CleanerService cleanerService;
+
+ @Mock
+ private ObjectMapper objectMapper;
+
+ @BeforeEach
+ public void setUp() {
+ MockitoAnnotations.openMocks(this);
+ }
+
+ @Test
+ public void testExtractApiResponse() throws IOException {
+ String json = "{\"response_code\":200,\"results\":[{\"type\":\"multiple choice\",\"difficulty\":\"easy\",\"category\":\"general knowledge\",\"question\":\"What is the capital of France?\",\"correct_answer\":\"Paris\",\"incorrect_answers\":[\"Berlin\",\"Madrid\",\"Rome\"]}]}"; // Example JSON input
+
+ Question question = new Question();
+ question.setType("multiple choice");
+ question.setDifficulty("easy");
+ question.setCategory("general knowledge");
+ question.setQuestion("What is the capital of France?");
+ question.setCorrectAnswer("Paris");
+ question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+
+ ApiResponse expectedResponse = new ApiResponse();
+ expectedResponse.setResponseCode(200);
+ expectedResponse.setResults(Arrays.asList(question));
+ when(objectMapper.readValue(json, ApiResponse.class)).thenReturn(expectedResponse);
+
+ ApiResponse actualResponse = cleanerService.extractApiResponse(json);
+ assertThat(actualResponse).isNotNull();
+ assertThat(actualResponse.getResponseCode()).isEqualTo(expectedResponse.getResponseCode());
+ assertThat(actualResponse.getResults()).isNotEmpty();
+ assertThat(actualResponse.getResults().get(0).getQuestion()).isEqualTo(question.getQuestion());
+ verify(objectMapper, times(1)).readValue(json, ApiResponse.class);
+ }
+}
\ No newline at end of file
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.java b/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.java
new file mode 100644
index 0000000..2fe0683
--- /dev/null
+++ b/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.java
@@ -0,0 +1,105 @@
+package com.ninjaws.quiz.services;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import com.ninjaws.quiz.models.Question;
+import com.ninjaws.quiz.repositories.QuestionRepository;
+
+public class DataServiceTest {
+
+ @InjectMocks
+ private DataService dataService;
+
+ @Mock
+ private QuestionRepository questionRepository;
+
+ private Question question;
+
+
+ @BeforeEach
+ public void setUp() {
+ MockitoAnnotations.openMocks(this);
+
+ question = new Question();
+ question.setType("multiple choice");
+ question.setDifficulty("easy");
+ question.setCategory("general knowledge");
+ question.setQuestion("What is the capital of France?");
+ question.setCorrectAnswer("Paris");
+ question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+ }
+
+ @Test
+ public void testSaveQuestion() {
+ when(questionRepository.save(any(Question.class))).thenReturn(question);
+
+ Question savedQuestion = dataService.saveQuestion(question);
+ assertThat(savedQuestion).isNotNull();
+ assertThat(savedQuestion.getQuestion()).isEqualTo("What is the capital of France?");
+ verify(questionRepository, times(1)).save(question);
+ }
+
+ @Test
+ public void testGetAllQuestions() {
+ when(questionRepository.findAll()).thenReturn(Arrays.asList(question));
+
+ List questions = dataService.getAllQuestions();
+ assertThat(questions).isNotEmpty();
+ assertThat(questions.size()).isEqualTo(1);
+ assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
+ verify(questionRepository, times(1)).findAll();
+ }
+
+ @Test
+ public void testFindQuestionById() {
+ when(questionRepository.findById(any(Long.class))).thenReturn(Optional.of(question));
+
+ Optional foundQuestion = questionRepository.findById(1L);
+ assertThat(foundQuestion).isPresent();
+ assertThat(foundQuestion.get().getQuestion()).isEqualTo("What is the capital of France?");
+ verify(questionRepository, times(1)).findById(1L);
+ }
+
+ @Test
+ public void testSaveQuestions() {
+ Question question1 = new Question();
+ question1.setType("multiple choice");
+ question1.setDifficulty("easy");
+ question1.setCategory("general knowledge");
+ question1.setQuestion("What is the capital of France?");
+ question1.setCorrectAnswer("Paris");
+ question1.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+
+ Question question2 = new Question();
+ question2.setType("multiple choice");
+ question2.setDifficulty("medium");
+ question2.setCategory("science");
+ question2.setQuestion("What is the chemical symbol for water?");
+ question2.setCorrectAnswer("H2O");
+ question2.setIncorrectAnswers(Arrays.asList("CO2", "O2", "NaCl"));
+
+ when(questionRepository.saveAll(anyList())).thenReturn(Arrays.asList(question1, question2));
+
+ List questions = dataService.saveQuestions(Arrays.asList(question1, question2));
+
+ assertThat(questions).hasSize(2);
+ assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
+ assertThat(questions.get(1).getQuestion()).isEqualTo("What is the chemical symbol for water?");
+ verify(questionRepository, times(1)).saveAll(anyList());
+ }
+}
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/QueueServiceTest.java b/backend/src/test/java/com/ninjaws/quiz/services/QueueServiceTest.java
new file mode 100644
index 0000000..e921c04
--- /dev/null
+++ b/backend/src/test/java/com/ninjaws/quiz/services/QueueServiceTest.java
@@ -0,0 +1,63 @@
+package com.ninjaws.quiz.services;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.ninjaws.quiz.models.QuizSettings;
+import com.ninjaws.quiz.models.Request;
+
+public class QueueServiceTest {
+
+ private QueueService queueService;
+
+ @BeforeEach
+ public void setUp() {
+ queueService = new QueueService();
+ }
+
+ @Test
+ public void testAddToQueue() {
+ QuizSettings quizSettings = new QuizSettings();
+ Request request = new Request("session1", quizSettings);
+
+ boolean added = queueService.addToQueue(request);
+ assertTrue(added);
+
+ for (int i = 0; i < 4; i++) {
+ added = queueService.addToQueue(new Request("session" + (i + 2), new QuizSettings()));
+ assertTrue(added);
+ }
+
+ added = queueService.addToQueue(new Request("session6", new QuizSettings()));
+ assertFalse(added);
+ }
+
+ @Test
+ public void testPopFromQueue() {
+ QuizSettings quizSettings1 = new QuizSettings();
+ QuizSettings quizSettings2 = new QuizSettings();
+
+ Request request1 = new Request("session1", quizSettings1);
+ Request request2 = new Request("session2", quizSettings2);
+
+ queueService.addToQueue(request1);
+ queueService.addToQueue(request2);
+
+ Request poppedRequest = queueService.popFromQueue();
+ assertEquals(request1, poppedRequest);
+
+ poppedRequest = queueService.popFromQueue();
+ assertEquals(request2, poppedRequest);
+
+ assertNull(queueService.popFromQueue());
+ }
+
+ @Test
+ public void testPopFromEmptyQueue() {
+ assertNull(queueService.popFromQueue());
+ }
+}
\ No newline at end of file