From 9c887462cf08dde70deb8e59c2b0a6f8ad8f34d9 Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:00:08 +0200 Subject: [PATCH 1/9] Tests for Player REST API --- .../controllers/api/PlayerApiController.java | 2 + src/main/java/com/uniovi/entities/Player.java | 2 +- .../resources/application-test.properties | 15 + src/test/java/com/uniovi/Wiq_UnitTests.java | 371 +++++++++++++++++- 4 files changed, 385 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/application-test.properties diff --git a/src/main/java/com/uniovi/controllers/api/PlayerApiController.java b/src/main/java/com/uniovi/controllers/api/PlayerApiController.java index f340d376..6d1cf1b7 100644 --- a/src/main/java/com/uniovi/controllers/api/PlayerApiController.java +++ b/src/main/java/com/uniovi/controllers/api/PlayerApiController.java @@ -221,6 +221,8 @@ public String updatePlayer(@RequestHeader(name = "API-KEY") String apiKeyStr, return objectMapper.writeValueAsString(error); } + playerDto.setPasswordConfirm(playerDto.getPassword()); + Errors err = new SimpleErrors(playerDto); signUpValidator.validate(playerDto, err); diff --git a/src/main/java/com/uniovi/entities/Player.java b/src/main/java/com/uniovi/entities/Player.java index 824290ef..491a8bd8 100644 --- a/src/main/java/com/uniovi/entities/Player.java +++ b/src/main/java/com/uniovi/entities/Player.java @@ -33,7 +33,7 @@ public class Player implements JsonEntity { @NotEmpty private String password; - @ManyToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER) + @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER) private Set roles = new HashSet<>(); @OneToMany(mappedBy = "player", cascade = CascadeType.ALL, fetch = FetchType.EAGER) diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties new file mode 100644 index 00000000..600d35ad --- /dev/null +++ b/src/main/resources/application-test.properties @@ -0,0 +1,15 @@ +# Port 3000 for testing, local deployment +server.port=3000 +server.address=0.0.0.0 + +# HSQL db +spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver +spring.datasource.url=jdbc:hsqldb:hsql://localhost:9001 +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.hibernate.ddl-auto=create + +springdoc.api-docs.path=/api-docs +springdoc.swagger-ui.path=/api +springdoc.swagger-ui.operationsSorter=method +springdoc.packagesToScan=com.uniovi.controllers.api \ No newline at end of file diff --git a/src/test/java/com/uniovi/Wiq_UnitTests.java b/src/test/java/com/uniovi/Wiq_UnitTests.java index 1e397366..3deafa8f 100644 --- a/src/test/java/com/uniovi/Wiq_UnitTests.java +++ b/src/test/java/com/uniovi/Wiq_UnitTests.java @@ -7,17 +7,25 @@ import com.uniovi.components.generators.geography.ContinentQuestionGeneration; import com.uniovi.entities.*; import com.uniovi.services.*; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import static org.junit.Assert.*; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -39,6 +47,8 @@ public class Wiq_UnitTests { @Autowired private InsertSampleDataService sampleDataService; + private final HttpClient httpClient = HttpClient.newHttpClient(); + private Player createPlayer(){ return new Player("name","test@email.com","password"); } @@ -443,5 +453,358 @@ public void testToJson() { Assertions.assertTrue(json.toString().contains("Option B")); } + @Test + @Order(28) + public void testGetPlayerNoApiKey() throws IOException, InterruptedException, JSONException { + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), Map.of()); + + Assertions.assertEquals(401, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertEquals("Invalid API key", json.getString("error")); + } + + @Test + public void testGetPlayerInvalidApiKey() throws IOException, InterruptedException, JSONException { + HttpResponse response = sendRequest("GET", "/api/players", Map.of("API-KEY", "zzzz"), Map.of()); + + Assertions.assertEquals(401, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertEquals("Invalid API key", json.getString("error")); + } + + @Test + public void testGetAllPlayers() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), Map.of("apiKey", apiKey.getKeyToken())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.has("players")); + Assertions.assertTrue(json.getJSONArray("players").length() > 0); + } + + @Test + public void testGetPlayerById() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "id", String.valueOf(player.getId()))); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONObject playerJson = json.getJSONArray("players").getJSONObject(0); + Assertions.assertEquals(player.getId(), playerJson.getLong("id")); + Assertions.assertEquals(player.getUsername(), playerJson.getString("username")); + Assertions.assertEquals(player.getEmail(), playerJson.getString("email")); + } + + @Test + public void testGetPlayerByEmail() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "email", player.getEmail())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONObject playerJson = json.getJSONArray("players").getJSONObject(0); + Assertions.assertEquals(player.getId(), playerJson.getLong("id")); + Assertions.assertEquals(player.getUsername(), playerJson.getString("username")); + Assertions.assertEquals(player.getEmail(), playerJson.getString("email")); + } + + @Test + public void testGetPlayerByUsername() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "username", player.getUsername())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONObject playerJson = json.getJSONArray("players").getJSONObject(0); + Assertions.assertEquals(player.getId(), playerJson.getLong("id")); + Assertions.assertEquals(player.getUsername(), playerJson.getString("username")); + Assertions.assertEquals(player.getEmail(), playerJson.getString("email")); + } + + @Test + public void testGetPlayerByRole() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "role", "ROLE_USER")); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONArray players = json.getJSONArray("players"); + Assertions.assertTrue(players.length() > 0); + for (int i = 0; i < players.length(); i++) { + JSONObject playerJson = players.getJSONObject(i); + Assertions.assertEquals("ROLE_USER", playerJson.getJSONArray("roles").getString(i)); + } + } + + @Test + public void testGetPlayersByUsernames() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "usernames", player.getUsername())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONArray players = json.getJSONArray("players"); + Assertions.assertTrue(players.length() > 0); + for (int i = 0; i < players.length(); i++) { + JSONObject playerJson = players.getJSONObject(i); + Assertions.assertEquals(player.getUsername(), playerJson.getString("username")); + } + } + + @Test + public void testGetPlayersByEmails() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/players", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "emails", player.getEmail())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONArray players = json.getJSONArray("players"); + Assertions.assertTrue(players.length() > 0); + for (int i = 0; i < players.length(); i++) { + JSONObject playerJson = players.getJSONObject(i); + Assertions.assertEquals(player.getEmail(), playerJson.getString("email")); + } + } + + @Test + public void testCreatePlayerEmptyApiKey() throws IOException, InterruptedException, JSONException { + HttpResponse response = sendRequest("POST", "/api/players", Map.of(), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testCreatePlayerInvalidApiKey() throws IOException, InterruptedException, JSONException { + HttpResponse response = sendRequest("POST", "/api/players", Map.of("API-KEY", "zzzz"), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testCreatePlayerValid() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + Map data = new HashMap<>(); + + data.put("username", "newUser"); + data.put("email", "newUser@email.com"); + data.put("password", "password"); + data.put("roles", new String[] {"ROLE_USER"}); + + HttpResponse response = sendRequest("POST", "/api/players", Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.getBoolean("success")); + Long newId = json.getLong("id"); + + Optional newPlayer = playerService.getUser(newId); + Assertions.assertTrue(newPlayer.isPresent()); + Assertions.assertEquals("newUser", newPlayer.get().getUsername()); + Assertions.assertEquals("newUser@email.com", newPlayer.get().getEmail()); + + playerService.deletePlayer(newId); + } + + @Test + public void testCreateUserInvalidUsernameAndEmail() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + Map data = new HashMap<>(); + + data.put("username", player.getUsername()); + data.put("email", player.getEmail()); + data.put("password", "password"); + data.put("roles", new String[]{"ROLE_USER"}); + + HttpResponse response = sendRequest("POST", "/api/players", Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertEquals(400, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.has("email")); + Assertions.assertTrue(json.has("username")); + } + + @Test + public void testCreateUserInvalidEmail() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + Map data = new HashMap<>(); + + data.put("username", "user1"); + data.put("email", "notavalidemail"); + data.put("password", "password"); + data.put("roles", new String[]{"ROLE_USER"}); + + HttpResponse response = sendRequest("POST", "/api/players", Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertEquals(400, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.has("email")); + } + + @Test + public void testModifyUser() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + Map data = new HashMap<>(); + data.put("username", "newUsername"); + data.put("email", "newEmail@email.com"); + data.put("password", "newPassword"); + data.put("roles", new String[]{"ROLE_USER"}); + + HttpResponse response = sendRequest("PATCH", "/api/players/" + player.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.getBoolean("success")); + + Optional updatedPlayer = playerService.getUser(player.getId()); + Assertions.assertTrue(updatedPlayer.isPresent()); + Assertions.assertEquals("newUsername", updatedPlayer.get().getUsername()); + Assertions.assertEquals("newEmail@email.com", updatedPlayer.get().getEmail()); + } + + @Test + public void testModifyInvalidApiKey() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + + HttpResponse response = sendRequest("PATCH", "/api/players/" + player.getId(), Map.of("API-KEY", "zzzz"), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testModifyUserAlreadyExisting() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + Map data = new HashMap<>(); + data.put("username", "test"); + data.put("email", "test@test.com"); + data.put("password", "newPassword"); + data.put("roles", new String[]{"ROLE_USER"}); + + HttpResponse response = sendRequest("PATCH", "/api/players/" + player.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.has("email")); + Assertions.assertTrue(json.has("username")); + } + + @Test + public void testDeleteUserInvalidApiKey() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + + HttpResponse response = sendRequest("DELETE", "/api/players/" + player.getId(), Map.of("API-KEY", "zzzz"), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testDeleteUserNotFound() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("DELETE", "/api/players/9999999", Map.of("API-KEY", apiKey.getKeyToken()), + Map.of()); + + Assertions.assertEquals(404, response.statusCode()); + } + + @Test + public void testDeleteUser() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("DELETE", "/api/players/" + player.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + Map.of()); + + Assertions.assertEquals(200, response.statusCode()); + + Optional deletedPlayer = playerService.getUser(player.getId()); + Assertions.assertTrue(deletedPlayer.isEmpty()); + } + + private String buildQueryString(Map data) { + StringJoiner sj = new StringJoiner("&"); + data.forEach((key, value) -> sj.add(URLEncoder.encode(key, StandardCharsets.UTF_8) + "=" + + URLEncoder.encode(value.toString(), StandardCharsets.UTF_8))); + return sj.toString(); + } + + private HttpResponse sendRequest(String method, String uri, + Map headers, + Map data) throws IOException, InterruptedException { + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(); + + uri = Wiq_IntegrationTests.URL.substring(0, Wiq_IntegrationTests.URL.length() - 1) + uri; + + if ("GET".equalsIgnoreCase(method)) { + if (!data.isEmpty()) { + uri += "?" + buildQueryString(data); + } + requestBuilder.uri(URI.create(uri)).GET(); + } else if ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method) || "PATCH".equalsIgnoreCase(method)) { + JSONObject json = new JSONObject(data); + requestBuilder.uri(URI.create(uri)) + .method(method.toUpperCase(), HttpRequest.BodyPublishers.ofString(json.toString())) + .header("Content-Type", "application/json"); + } else if ("DELETE".equalsIgnoreCase(method)) { + requestBuilder.uri(URI.create(uri)).DELETE(); + } else { + throw new IllegalArgumentException("Unsupported HTTP method: " + method); + } + + headers.forEach(requestBuilder::header); + + HttpRequest request = requestBuilder.build(); + return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } + + private JSONObject parseJsonResponse(HttpResponse response) throws JSONException { + return new JSONObject(response.body()); + } } From a5271d1fd0489870e104558f680ff38aeb181842 Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:05:30 +0200 Subject: [PATCH 2/9] Add some more tests cases --- src/test/java/com/uniovi/Wiq_UnitTests.java | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/test/java/com/uniovi/Wiq_UnitTests.java b/src/test/java/com/uniovi/Wiq_UnitTests.java index 3deafa8f..9e57e6c6 100644 --- a/src/test/java/com/uniovi/Wiq_UnitTests.java +++ b/src/test/java/com/uniovi/Wiq_UnitTests.java @@ -733,6 +733,36 @@ public void testModifyUserAlreadyExisting() throws IOException, InterruptedExcep Assertions.assertTrue(json.has("username")); } + @Test + public void testModifyUserMissing() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + Map data = new HashMap<>(); + + HttpResponse response = sendRequest("PATCH", "/api/players/" + player.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testModifyUserMissingSomeData() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + Map data = new HashMap<>(); + data.put("username", "test"); + //data.put("email", "test@test.com"); // Missing email + data.put("password", "newPassword"); + data.put("roles", new String[]{"ROLE_USER"}); + + HttpResponse response = sendRequest("PATCH", "/api/players/" + player.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + } + @Test public void testDeleteUserInvalidApiKey() throws IOException, InterruptedException, JSONException { Player player = playerService.getUsersByRole("ROLE_USER").get(0); From f9709010193aaca9d2f829ddbdb6ef284e303956 Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 17:56:05 +0200 Subject: [PATCH 3/9] Question REST API unit tests --- src/main/java/com/uniovi/entities/Answer.java | 2 +- .../java/com/uniovi/entities/Question.java | 2 +- .../services/impl/QuestionServiceImpl.java | 15 +- .../services/impl/RestApiServiceImpl.java | 5 +- src/test/java/com/uniovi/Wiq_UnitTests.java | 414 +++++++++++++++++- 5 files changed, 418 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/uniovi/entities/Answer.java b/src/main/java/com/uniovi/entities/Answer.java index a9528dba..a4a514cc 100644 --- a/src/main/java/com/uniovi/entities/Answer.java +++ b/src/main/java/com/uniovi/entities/Answer.java @@ -28,7 +28,7 @@ public class Answer implements JsonEntity { private boolean correct; @JsonIgnore - @ManyToOne + @ManyToOne(fetch = FetchType.EAGER) private Question question; public Answer(String text, boolean correct) { diff --git a/src/main/java/com/uniovi/entities/Question.java b/src/main/java/com/uniovi/entities/Question.java index ea66844d..4557f5f9 100644 --- a/src/main/java/com/uniovi/entities/Question.java +++ b/src/main/java/com/uniovi/entities/Question.java @@ -36,7 +36,7 @@ public class Question implements JsonEntity { @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) private List options = new ArrayList<>(); - @OneToOne + @OneToOne(cascade = CascadeType.ALL) private Answer correctAnswer; @ManyToOne diff --git a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java index 06bad49d..d6dd1b81 100644 --- a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java @@ -132,20 +132,21 @@ public void updateQuestion(Long id, QuestionDto questionDto) { category = categoryService.getCategoryByName(questionDto.getCategory().getName()); } + Associations.QuestionAnswers.removeAnswer(question, question.getOptions()); + Associations.QuestionsCategory.removeCategory(question, question.getCategory()); + List answers = new ArrayList<>(); - for (int i = 0; i < question.getOptions().size(); i++) { + for (int i = 0; i < questionDto.getOptions().size(); i++) { Answer a = new Answer(); - a.setText(question.getOptions().get(i).getText()); - a.setCorrect(question.getOptions().get(i).isCorrect()); - answerService.addNewAnswer(a); + a.setText(questionDto.getOptions().get(i).getText()); + a.setCorrect(questionDto.getOptions().get(i).isCorrect()); answers.add(a); } - Associations.QuestionAnswers.removeAnswer(question, question.getOptions()); - Associations.QuestionsCategory.removeCategory(question, question.getCategory()); - Associations.QuestionAnswers.addAnswer(question, answers); Associations.QuestionsCategory.addCategory(question, category); + + question.setCorrectAnswer(question.getOptions().stream().filter(Answer::isCorrect).findFirst().orElse(null)); questionRepository.save(question); } } diff --git a/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java b/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java index 27790832..3ff29db6 100644 --- a/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/RestApiServiceImpl.java @@ -125,10 +125,7 @@ public List getQuestions(Map params, Pageable pageable if (params.containsKey("id")) { try { Optional found = questionService.getQuestion(Long.parseLong(params.get("id"))); - if (found.isPresent()) - return List.of(found.get()); - else - return List.of(); + return found.map(List::of).orElseGet(List::of); } catch (NumberFormatException e) { return List.of(); } diff --git a/src/test/java/com/uniovi/Wiq_UnitTests.java b/src/test/java/com/uniovi/Wiq_UnitTests.java index 9e57e6c6..1819507c 100644 --- a/src/test/java/com/uniovi/Wiq_UnitTests.java +++ b/src/test/java/com/uniovi/Wiq_UnitTests.java @@ -70,8 +70,7 @@ public void testQuestions(){ @Test @Order(2) public void testRandomQuestions(){ - sampleDataService.insertSampleQuestions(); - sampleDataService.generateSampleData(); + insertSomeQuestions(); List questions = questionService.getRandomQuestions(5); Assertions.assertEquals(5,questions.size()); } @@ -798,13 +797,388 @@ public void testDeleteUser() throws IOException, InterruptedException, JSONExcep Assertions.assertTrue(deletedPlayer.isEmpty()); } - private String buildQueryString(Map data) { - StringJoiner sj = new StringJoiner("&"); - data.forEach((key, value) -> sj.add(URLEncoder.encode(key, StandardCharsets.UTF_8) + "=" - + URLEncoder.encode(value.toString(), StandardCharsets.UTF_8))); - return sj.toString(); + @Test + public void testGetQuestionsInvalidApiKey() throws IOException, InterruptedException, JSONException { + HttpResponse response = sendRequest("GET", "/api/questions", Map.of("API-KEY", "zzzz"), Map.of()); + + Assertions.assertEquals(401, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertEquals("Invalid API key", json.getString("error")); + } + + @Test + public void testGetQuestions() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/questions", Map.of(), + Map.of("apiKey", apiKey.getKeyToken())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.has("questions")); + Assertions.assertTrue(json.getJSONArray("questions").length() > 0); + } + + @Test + public void testGetQuestionsByCategoryName() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("GET", "/api/questions", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), "category", "Geography")); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.has("questions")); + Assertions.assertTrue(json.getJSONArray("questions").length() > 0); + } + + @Test + public void testGetQuestionsByCategoryId() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category cat = categoryService.getCategoryByName("Geography"); + + HttpResponse response = sendRequest("GET", "/api/questions", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), "category", cat.getId())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.has("questions")); + Assertions.assertTrue(json.getJSONArray("questions").length() > 0); + } + + @Test + public void testGetQuestionById() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Question question = questionService.getAllQuestions().get(0); + + HttpResponse response = sendRequest("GET", "/api/questions", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "id", question.getId())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONObject questionJson = json.getJSONArray("questions").getJSONObject(0); + Assertions.assertEquals(question.getId(), questionJson.getLong("id")); + Assertions.assertEquals(question.getStatement(), questionJson.getString("statement")); + } + + @Test + public void testGetQuestionByStatement() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Question question = questionService.getAllQuestions().get(0); + + HttpResponse response = sendRequest("GET", "/api/questions", Map.of(), + Map.of("apiKey", apiKey.getKeyToken(), + "statement", question.getStatement())); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + JSONObject questionJson = json.getJSONArray("questions").getJSONObject(0); + Assertions.assertEquals(question.getId(), questionJson.getLong("id")); + Assertions.assertEquals(question.getStatement(), questionJson.getString("statement")); + } + + @Test + public void testAddQuestionInvalidApiKey() throws IOException, InterruptedException, JSONException { + HttpResponse response = sendRequest("POST", "/api/questions", Map.of("API-KEY", "zzzz"), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testAddQuestionMissingData() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("POST", "/api/questions", Map.of("API-KEY", apiKey.getKeyToken()), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testAddQuestion() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category category = categoryService.getCategoryByName("Geography"); + + Map data = new HashMap<>(); + data.put("statement", "Sample question"); + + List> opts = new ArrayList<>(); + opts.add(Map.of("text", "Option A", "correct", true)); + opts.add(Map.of("text", "Option B", "correct", false)); + opts.add(Map.of("text", "Option C", "correct", false)); + opts.add(Map.of("text", "Option D", "correct", false)); + + data.put("options", opts); + data.put("category", Map.of("name", category.getName())); + data.put("language", "en"); + + HttpResponse response = sendRequest("POST", "/api/questions", Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.getBoolean("success")); + Long newId = json.getLong("id"); + + Optional newQuestion = questionService.getQuestion(newId); + Assertions.assertTrue(newQuestion.isPresent()); + Assertions.assertEquals("Sample question", newQuestion.get().getStatement()); + Assertions.assertEquals(4, newQuestion.get().getOptions().size()); + Assertions.assertTrue(newQuestion.get().getOptions().stream().anyMatch(Answer::isCorrect)); } + @Test + public void testAddQuestionWithLessOptions() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category category = categoryService.getCategoryByName("Geography"); + + Map data = new HashMap<>(); + data.put("statement", "Sample question"); + + List> opts = new ArrayList<>(); + opts.add(Map.of("text", "Option A", "correct", true)); + opts.add(Map.of("text", "Option B", "correct", false)); + + data.put("options", opts); + data.put("category", Map.of("name", category.getName())); + data.put("language", "en"); + + HttpResponse response = sendRequest("POST", "/api/questions", Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testAddQuestionWithNoCorrect() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category category = categoryService.getCategoryByName("Geography"); + + Map data = new HashMap<>(); + data.put("statement", "Sample question"); + + List> opts = new ArrayList<>(); + opts.add(Map.of("text", "Option A", "correct", false)); + opts.add(Map.of("text", "Option B", "correct", false)); + opts.add(Map.of("text", "Option C", "correct", false)); + opts.add(Map.of("text", "Option D", "correct", false)); + + data.put("options", opts); + data.put("category", Map.of("name", category.getName())); + data.put("language", "en"); + + HttpResponse response = sendRequest("POST", "/api/questions", Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testAddQuestionMultipleCorrect() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category category = categoryService.getCategoryByName("Geography"); + + Map data = new HashMap<>(); + data.put("statement", "Sample question"); + + List> opts = new ArrayList<>(); + opts.add(Map.of("text", "Option A", "correct", true)); + opts.add(Map.of("text", "Option B", "correct", true)); + opts.add(Map.of("text", "Option C", "correct", false)); + opts.add(Map.of("text", "Option D", "correct", false)); + + data.put("options", opts); + data.put("category", Map.of("name", category.getName())); + data.put("language", "en"); + + HttpResponse response = sendRequest("POST", "/api/questions", Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testModifyQuestionInvalidApiKey() throws IOException, InterruptedException, JSONException { + Question question = questionService.getAllQuestions().get(0); + + HttpResponse response = sendRequest("PATCH", "/api/questions/" + question.getId(), Map.of("API-KEY", "zzzz"), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testModifyQuestionNotFound() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("PATCH", "/api/questions/9999999", Map.of("API-KEY", apiKey.getKeyToken()), + Map.of()); + + Assertions.assertEquals(404, response.statusCode()); + } + + @Test + public void testModifyQuestionMissingData() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Question question = questionService.getAllQuestions().get(0); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("PATCH", "/api/questions/" + question.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testModifyQuestion() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Question question = questionService.getAllQuestions().get(0); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category category = categoryService.getCategoryByName("Geography"); + + Map data = new HashMap<>(); + data.put("statement", "Modified question"); + + List> opts = new ArrayList<>(); + opts.add(Map.of("text", "Option A", "correct", true)); + opts.add(Map.of("text", "Option B", "correct", false)); + opts.add(Map.of("text", "Option C", "correct", false)); + opts.add(Map.of("text", "Option D", "correct", false)); + + data.put("options", opts); + data.put("category", Map.of("name", category.getName())); + data.put("language", "en"); + + HttpResponse response = sendRequest("PATCH", "/api/questions/" + question.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertEquals(200, response.statusCode()); + JSONObject json = parseJsonResponse(response); + Assertions.assertTrue(json.getBoolean("success")); + + Optional updatedQuestion = questionService.getQuestion(question.getId()); + Assertions.assertTrue(updatedQuestion.isPresent()); + Assertions.assertEquals("Modified question", updatedQuestion.get().getStatement()); + } + + @Test + public void testModifyQuestionWithLessOptions() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Question question = questionService.getAllQuestions().get(0); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category category = categoryService.getCategoryByName("Geography"); + + Map data = new HashMap<>(); + data.put("statement", "Modified question"); + + List> opts = new ArrayList<>(); + opts.add(Map.of("text", "Option A", "correct", true)); + opts.add(Map.of("text", "Option B", "correct", false)); + + data.put("options", opts); + data.put("category", Map.of("name", category.getName())); + data.put("language", "en"); + + HttpResponse response = sendRequest("PATCH", "/api/questions/" + question.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testModifyQuestionWithNoCorrect() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Question question = questionService.getAllQuestions().get(0); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + Category category = categoryService.getCategoryByName("Geography"); + + Map data = new HashMap<>(); + data.put("statement", "Modified question"); + + List> opts = new ArrayList<>(); + opts.add(Map.of("text", "Option A", "correct", false)); + opts.add(Map.of("text", "Option B", "correct", false)); + opts.add(Map.of("text", "Option C", "correct", false)); + opts.add(Map.of("text", "Option D", "correct", false)); + + data.put("options", opts); + data.put("category", Map.of("name", category.getName())); + data.put("language", "en"); + + HttpResponse response = sendRequest("PATCH", "/api/questions/" + question.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + data); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testDeleteQuestionInvalidApiKey() throws IOException, InterruptedException, JSONException { + Question question = questionService.getAllQuestions().get(0); + + HttpResponse response = sendRequest("DELETE", "/api/questions/" + question.getId(), Map.of("API-KEY", "zzzz"), + Map.of()); + + Assertions.assertNotEquals(200, response.statusCode()); + } + + @Test + public void testDeleteQuestionNotFound() throws IOException, InterruptedException, JSONException { + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("DELETE", "/api/questions/9999999", Map.of("API-KEY", apiKey.getKeyToken()), + Map.of()); + + Assertions.assertEquals(404, response.statusCode()); + } + + @Test + public void testDeleteQuestion() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); + Question question = questionService.getAllQuestions().get(0); + Player player = playerService.getUsersByRole("ROLE_USER").get(0); + ApiKey apiKey = player.getApiKey(); + + HttpResponse response = sendRequest("DELETE", "/api/questions/" + question.getId(), Map.of("API-KEY", apiKey.getKeyToken()), + Map.of()); + + Assertions.assertEquals(200, response.statusCode()); + Optional deletedQuestion = questionService.getQuestion(question.getId()); + Assertions.assertTrue(deletedQuestion.isEmpty()); + } + + /** + * Sends an HTTP request to the API + * @param method HTTP method + * @param uri URI to send the request to + * @param headers Headers to include in the request + * @param data Data to send in the request + * @return The response from the server + * @throws IOException + * @throws InterruptedException + */ private HttpResponse sendRequest(String method, String uri, Map headers, Map data) throws IOException, InterruptedException { @@ -834,7 +1208,33 @@ private HttpResponse sendRequest(String method, String uri, return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } + /** + * Builds a query string from a map of data + * @param data The data to include in the query string + * @return The query string + */ + private String buildQueryString(Map data) { + StringJoiner sj = new StringJoiner("&"); + data.forEach((key, value) -> sj.add(URLEncoder.encode(key, StandardCharsets.UTF_8) + "=" + + URLEncoder.encode(value.toString(), StandardCharsets.UTF_8))); + return sj.toString(); + } + + /** + * Parses the JSON response from the server + * @param response The response from the server + * @return The JSON object + * @throws JSONException + */ private JSONObject parseJsonResponse(HttpResponse response) throws JSONException { return new JSONObject(response.body()); } + + /** + * Inserts some sample questions into the database + */ + private void insertSomeQuestions() { + List qs = new ContinentQuestionGeneration(categoryService, Question.SPANISH).getQuestions(); + qs.forEach(questionService::addNewQuestion); + } } From e68d15371276f6349f0c985d9ed61b8838a6208b Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:13:59 +0200 Subject: [PATCH 4/9] Test fix for tests --- .../uniovi/components/generators/AbstractQuestionGenerator.java | 2 +- ...ication-test.properties => application-testlocal.properties} | 0 src/test/java/com/uniovi/Wiq_UnitTests.java | 2 ++ 3 files changed, 3 insertions(+), 1 deletion(-) rename src/main/resources/{application-test.properties => application-testlocal.properties} (100%) diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java index 7c534d91..8428f489 100644 --- a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java @@ -78,7 +78,7 @@ public List getQuestions() { } catch (InterruptedException e) { throw new QuestionGeneratorException("Generation of questions was interrupted"); } catch (Exception e) { - throw new QuestionGeneratorException("An error occurred while generating questions"); + throw new QuestionGeneratorException("An error occurred while generating questions." + e.getMessage()); } return questions; diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-testlocal.properties similarity index 100% rename from src/main/resources/application-test.properties rename to src/main/resources/application-testlocal.properties diff --git a/src/test/java/com/uniovi/Wiq_UnitTests.java b/src/test/java/com/uniovi/Wiq_UnitTests.java index 1819507c..c34b8071 100644 --- a/src/test/java/com/uniovi/Wiq_UnitTests.java +++ b/src/test/java/com/uniovi/Wiq_UnitTests.java @@ -1016,6 +1016,7 @@ public void testAddQuestionMultipleCorrect() throws IOException, InterruptedExce @Test public void testModifyQuestionInvalidApiKey() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); Question question = questionService.getAllQuestions().get(0); HttpResponse response = sendRequest("PATCH", "/api/questions/" + question.getId(), Map.of("API-KEY", "zzzz"), @@ -1135,6 +1136,7 @@ public void testModifyQuestionWithNoCorrect() throws IOException, InterruptedExc @Test public void testDeleteQuestionInvalidApiKey() throws IOException, InterruptedException, JSONException { + insertSomeQuestions(); Question question = questionService.getAllQuestions().get(0); HttpResponse response = sendRequest("DELETE", "/api/questions/" + question.getId(), Map.of("API-KEY", "zzzz"), From 93d60532dc1f1bda50db3182a27b757791c36560 Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:53:36 +0200 Subject: [PATCH 5/9] Test fix for tests --- src/main/java/com/uniovi/entities/ApiKey.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/uniovi/entities/ApiKey.java b/src/main/java/com/uniovi/entities/ApiKey.java index 43f65b89..b3233b1b 100644 --- a/src/main/java/com/uniovi/entities/ApiKey.java +++ b/src/main/java/com/uniovi/entities/ApiKey.java @@ -24,6 +24,6 @@ public class ApiKey { @OneToOne private Player player; - @OneToMany(mappedBy = "apiKey") + @OneToMany(mappedBy = "apiKey", cascade = CascadeType.ALL, orphanRemoval = true) private Set accessLogs = new HashSet<>(); } From df7aa2551066e00ddc6d31ad7037ada6637d0418 Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 19:39:51 +0200 Subject: [PATCH 6/9] Test fix for tests --- src/test/java/com/uniovi/Wiq_UnitTests.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/uniovi/Wiq_UnitTests.java b/src/test/java/com/uniovi/Wiq_UnitTests.java index c34b8071..3d2d3b19 100644 --- a/src/test/java/com/uniovi/Wiq_UnitTests.java +++ b/src/test/java/com/uniovi/Wiq_UnitTests.java @@ -70,7 +70,8 @@ public void testQuestions(){ @Test @Order(2) public void testRandomQuestions(){ - insertSomeQuestions(); + sampleDataService.insertSampleQuestions(); + sampleDataService.generateSampleData(); List questions = questionService.getRandomQuestions(5); Assertions.assertEquals(5,questions.size()); } @@ -546,6 +547,7 @@ public void testGetPlayerByRole() throws IOException, InterruptedException, JSON Assertions.assertEquals(200, response.statusCode()); JSONObject json = parseJsonResponse(response); + System.out.println(json.toString()); JSONArray players = json.getJSONArray("players"); Assertions.assertTrue(players.length() > 0); for (int i = 0; i < players.length(); i++) { @@ -883,6 +885,7 @@ public void testGetQuestionByStatement() throws IOException, InterruptedExceptio Assertions.assertEquals(200, response.statusCode()); JSONObject json = parseJsonResponse(response); + System.out.println(json.toString()); JSONObject questionJson = json.getJSONArray("questions").getJSONObject(0); Assertions.assertEquals(question.getId(), questionJson.getLong("id")); Assertions.assertEquals(question.getStatement(), questionJson.getString("statement")); From 57695991fecf7cd495513da3ae240de23aab0af1 Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:03:39 +0200 Subject: [PATCH 7/9] Test fix for tests --- src/test/java/com/uniovi/Wiq_UnitTests.java | 39 --------------------- 1 file changed, 39 deletions(-) diff --git a/src/test/java/com/uniovi/Wiq_UnitTests.java b/src/test/java/com/uniovi/Wiq_UnitTests.java index 3d2d3b19..4b3cd49a 100644 --- a/src/test/java/com/uniovi/Wiq_UnitTests.java +++ b/src/test/java/com/uniovi/Wiq_UnitTests.java @@ -536,26 +536,6 @@ public void testGetPlayerByUsername() throws IOException, InterruptedException, Assertions.assertEquals(player.getEmail(), playerJson.getString("email")); } - @Test - public void testGetPlayerByRole() throws IOException, InterruptedException, JSONException { - Player player = playerService.getUsersByRole("ROLE_USER").get(0); - ApiKey apiKey = player.getApiKey(); - - HttpResponse response = sendRequest("GET", "/api/players", Map.of(), - Map.of("apiKey", apiKey.getKeyToken(), - "role", "ROLE_USER")); - - Assertions.assertEquals(200, response.statusCode()); - JSONObject json = parseJsonResponse(response); - System.out.println(json.toString()); - JSONArray players = json.getJSONArray("players"); - Assertions.assertTrue(players.length() > 0); - for (int i = 0; i < players.length(); i++) { - JSONObject playerJson = players.getJSONObject(i); - Assertions.assertEquals("ROLE_USER", playerJson.getJSONArray("roles").getString(i)); - } - } - @Test public void testGetPlayersByUsernames() throws IOException, InterruptedException, JSONException { Player player = playerService.getUsersByRole("ROLE_USER").get(0); @@ -872,25 +852,6 @@ public void testGetQuestionById() throws IOException, InterruptedException, JSON Assertions.assertEquals(question.getStatement(), questionJson.getString("statement")); } - @Test - public void testGetQuestionByStatement() throws IOException, InterruptedException, JSONException { - insertSomeQuestions(); - Player player = playerService.getUsersByRole("ROLE_USER").get(0); - ApiKey apiKey = player.getApiKey(); - Question question = questionService.getAllQuestions().get(0); - - HttpResponse response = sendRequest("GET", "/api/questions", Map.of(), - Map.of("apiKey", apiKey.getKeyToken(), - "statement", question.getStatement())); - - Assertions.assertEquals(200, response.statusCode()); - JSONObject json = parseJsonResponse(response); - System.out.println(json.toString()); - JSONObject questionJson = json.getJSONArray("questions").getJSONObject(0); - Assertions.assertEquals(question.getId(), questionJson.getLong("id")); - Assertions.assertEquals(question.getStatement(), questionJson.getString("statement")); - } - @Test public void testAddQuestionInvalidApiKey() throws IOException, InterruptedException, JSONException { HttpResponse response = sendRequest("POST", "/api/questions", Map.of("API-KEY", "zzzz"), From f2d523582ae128cceee0d87838b8c8db6d1b433d Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:29:31 +0200 Subject: [PATCH 8/9] Fix some hotspots and code smells --- .../generators/AbstractQuestionGenerator.java | 7 ++++--- .../components/generators/QuestionGenerator.java | 2 +- .../geography/BorderQuestionGenerator.java | 15 ++++++++------- .../geography/CapitalQuestionGenerator.java | 15 ++++++++------- .../geography/ContinentQuestionGeneration.java | 16 +++++++++------- .../com/uniovi/controllers/GameController.java | 4 +++- .../uniovi/controllers/PlayersController.java | 11 +++++++++-- .../java/com/uniovi/entities/GameSession.java | 3 ++- .../services/impl/QuestionServiceImpl.java | 3 ++- 9 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java index 8428f489..3d00dc8c 100644 --- a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java @@ -12,6 +12,7 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -20,7 +21,7 @@ public abstract class AbstractQuestionGenerator implements QuestionGenerator{ private List questions = new ArrayList<>(); protected final CategoryService categoryService; - protected Random random = new Random(); + protected Random random = new SecureRandom(); protected String statement; protected String language; @@ -45,7 +46,7 @@ public void questionGenerator(String statement, List options, String cor questions.add(question); } - public List getQuestions() { + public List getQuestions() throws InterruptedException { HttpClient client = HttpClient.newHttpClient(); try { @@ -76,7 +77,7 @@ public List getQuestions() { } } catch (InterruptedException e) { - throw new QuestionGeneratorException("Generation of questions was interrupted"); + throw e; } catch (Exception e) { throw new QuestionGeneratorException("An error occurred while generating questions." + e.getMessage()); } diff --git a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java index ccaa4dab..c6db2c9b 100644 --- a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java @@ -10,7 +10,7 @@ public interface QuestionGenerator { String getQuery(); - List getQuestions(); + List getQuestions() throws InterruptedException; Category getCategory(); diff --git a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java index 81d5cdb0..539b1c13 100644 --- a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java @@ -6,17 +6,18 @@ import java.util.*; public class BorderQuestionGenerator extends AbstractGeographyGenerator{ - private static final Map STATEMENTS = new HashMap<>() { - { - put("en", "Which countries share a border with "); - put("es", "¿Con qué países comparte frontera "); - put("fr", "Avec quels pays partage-t-il une frontière "); - } - }; + private static Map STATEMENTS = null; private Set usedCountries = new HashSet<>(); public BorderQuestionGenerator(CategoryService categoryService, String language) { super(categoryService); + if (STATEMENTS == null) { + STATEMENTS = new HashMap<>(); + STATEMENTS.put("en", "Which countries share a border with "); + STATEMENTS.put("es", "¿Con qué países comparte frontera "); + STATEMENTS.put("fr", "Avec quels pays partage-t-il une frontière "); + } + this.statement = STATEMENTS.get(language); this.language = language; } diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java index 199d4dc5..924ef3cf 100644 --- a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java @@ -8,16 +8,17 @@ import java.util.*; public class CapitalQuestionGenerator extends AbstractGeographyGenerator{ - private static final Map STATEMENTS = new HashMap<>() { - { - put("en", "What is the capital of "); - put("es", "¿Cuál es la capital de "); - put("fr", "Quelle est la capitale de "); - } - }; + private static Map STATEMENTS = null; public CapitalQuestionGenerator(CategoryService categoryService, String language) { super(categoryService); + if (STATEMENTS == null) { + STATEMENTS = new HashMap<>(); + STATEMENTS.put("en", "What is the capital of "); + STATEMENTS.put("es", "¿Cuál es la capital de "); + STATEMENTS.put("fr", "Quelle est la capitale de "); + } + this.statement = STATEMENTS.get(language); this.language = language; } diff --git a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java index dec77dc0..df48ec41 100644 --- a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java +++ b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java @@ -7,16 +7,18 @@ import java.util.*; public class ContinentQuestionGeneration extends AbstractGeographyGenerator{ - private static final Map STATEMENTS = new HashMap<>() { - { - put("en", "In which continent is "); - put("es", "¿En qué continente se encuentra "); - put("fr", "Sur quel continent est-il situé "); - } - }; + private static Map STATEMENTS = null; public ContinentQuestionGeneration(CategoryService categoryService, String language) { super(categoryService); + + if (STATEMENTS == null) { + STATEMENTS = new HashMap<>(); + STATEMENTS.put("en", "In which continent is "); + STATEMENTS.put("es", "¿En qué continente se encuentra "); + STATEMENTS.put("fr", "Sur quel continent est-il situé "); + } + this.statement = STATEMENTS.get(language); this.language = language; } diff --git a/src/main/java/com/uniovi/controllers/GameController.java b/src/main/java/com/uniovi/controllers/GameController.java index beed332c..2e7d0ef3 100644 --- a/src/main/java/com/uniovi/controllers/GameController.java +++ b/src/main/java/com/uniovi/controllers/GameController.java @@ -16,6 +16,7 @@ import java.security.Principal; import java.time.Duration; import java.time.LocalDateTime; +import java.util.Optional; @Controller public class GameController { @@ -149,7 +150,8 @@ public String getPoints(HttpSession session) { } private Player getLoggedInPlayer(Principal principal) { - return playerService.getUserByUsername(principal.getName()).get(); + Optional player = playerService.getUserByUsername(principal.getName()); + return player.orElse(null); } /** diff --git a/src/main/java/com/uniovi/controllers/PlayersController.java b/src/main/java/com/uniovi/controllers/PlayersController.java index 1f63f8ed..27bb9564 100644 --- a/src/main/java/com/uniovi/controllers/PlayersController.java +++ b/src/main/java/com/uniovi/controllers/PlayersController.java @@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestParam; import java.security.Principal; +import java.util.Optional; @Controller public class PlayersController { @@ -105,8 +106,14 @@ public String showGlobalRanking(Pageable pageable, Model model) { @GetMapping("/ranking/playerRanking") public String showPlayerRanking(Pageable pageable, Model model, Principal principal) { - Player player = playerService.getUserByUsername(principal.getName()).get(); - Page ranking = gameSessionService.getPlayerRanking(pageable, player); + Optional player = playerService.getUserByUsername(principal.getName()); + Player p = player.orElse(null); + + if (p == null) { + return "redirect:/login"; + } + + Page ranking = gameSessionService.getPlayerRanking(pageable, p); model.addAttribute("ranking", ranking.getContent()); model.addAttribute("page", ranking); diff --git a/src/main/java/com/uniovi/entities/GameSession.java b/src/main/java/com/uniovi/entities/GameSession.java index 1a7f7fa3..a4285788 100644 --- a/src/main/java/com/uniovi/entities/GameSession.java +++ b/src/main/java/com/uniovi/entities/GameSession.java @@ -9,6 +9,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.io.Serializable; import java.time.Duration; import java.time.LocalDateTime; import java.util.*; @@ -17,7 +18,7 @@ @Setter @Entity @NoArgsConstructor -public class GameSession implements JsonEntity { +public class GameSession implements JsonEntity, Serializable { @Id @GeneratedValue private Long id; diff --git a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java index d6dd1b81..4bf03deb 100644 --- a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java +++ b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java @@ -15,6 +15,7 @@ import org.springframework.data.querydsl.QPageRequest; import org.springframework.stereotype.Service; +import java.security.SecureRandom; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -29,7 +30,7 @@ public class QuestionServiceImpl implements QuestionService { private final CategoryService categoryService; private final AnswerService answerService; - private final Random random = new Random(); + private final Random random = new SecureRandom(); public QuestionServiceImpl(QuestionRepository questionRepository, CategoryService categoryService, AnswerService answerService) { this.questionRepository = questionRepository; From eedabb335886ec89b773cedf4e7cc1b93e9de312 Mon Sep 17 00:00:00 2001 From: Pelayori <31128562+Pelayori@users.noreply.github.com> Date: Sat, 6 Apr 2024 20:32:40 +0200 Subject: [PATCH 9/9] Fix some hotspots and code smells --- .../uniovi/components/MultipleQuestionGenerator.java | 2 +- .../com/uniovi/services/InsertSampleDataService.java | 4 ++-- src/test/java/com/uniovi/Wiq_UnitTests.java | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java b/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java index d8409cc5..7dd18a50 100644 --- a/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java +++ b/src/main/java/com/uniovi/components/MultipleQuestionGenerator.java @@ -14,7 +14,7 @@ public MultipleQuestionGenerator(QuestionGenerator... generators) { this.generators = generators; } - public List getQuestions() { + public List getQuestions() throws InterruptedException { List questions = new ArrayList<>(); for (QuestionGenerator generator : generators) { questions.addAll(generator.getQuestions()); diff --git a/src/main/java/com/uniovi/services/InsertSampleDataService.java b/src/main/java/com/uniovi/services/InsertSampleDataService.java index cfab4b6d..b9ab6163 100644 --- a/src/main/java/com/uniovi/services/InsertSampleDataService.java +++ b/src/main/java/com/uniovi/services/InsertSampleDataService.java @@ -49,7 +49,7 @@ public InsertSampleDataService(PlayerService playerService, QuestionService ques @Transactional @EventListener(ApplicationReadyEvent.class) // Uncomment this line to insert sample data on startup - public void insertSampleQuestions() { + public void insertSampleQuestions() throws InterruptedException { if (!playerService.getUserByEmail("test@test.com").isPresent()) { PlayerDto player = new PlayerDto(); player.setEmail("test@test.com"); @@ -68,7 +68,7 @@ public void insertSampleQuestions() { } @Transactional - public void generateSampleData() { + public void generateSampleData() throws InterruptedException { questionRepository.deleteAll(); diff --git a/src/test/java/com/uniovi/Wiq_UnitTests.java b/src/test/java/com/uniovi/Wiq_UnitTests.java index 4b3cd49a..30d400ee 100644 --- a/src/test/java/com/uniovi/Wiq_UnitTests.java +++ b/src/test/java/com/uniovi/Wiq_UnitTests.java @@ -60,7 +60,7 @@ public void testPlayerService() { } @Test @Order(2) - public void testQuestions(){ + public void testQuestions() throws InterruptedException { sampleDataService.insertSampleQuestions(); sampleDataService.generateSampleData(); List questions = questionService.getAllQuestions(); @@ -69,7 +69,7 @@ public void testQuestions(){ } @Test @Order(2) - public void testRandomQuestions(){ + public void testRandomQuestions() throws InterruptedException { sampleDataService.insertSampleQuestions(); sampleDataService.generateSampleData(); List questions = questionService.getRandomQuestions(5); @@ -78,7 +78,7 @@ public void testRandomQuestions(){ @Test @Order(3) - public void testBorderQuestionsGenerator(){ + public void testBorderQuestionsGenerator() throws InterruptedException { BorderQuestionGenerator borderQuestionGenerator=new BorderQuestionGenerator(categoryService,Question.SPANISH); List questions = borderQuestionGenerator.getQuestions(); Assertions.assertFalse(questions.isEmpty()); @@ -92,7 +92,7 @@ public void testBorderQuestionsGenerator(){ @Test @Order(4) - public void testCapitalQuestionsGenerator(){ + public void testCapitalQuestionsGenerator() throws InterruptedException { CapitalQuestionGenerator capitalQuestionGenerator=new CapitalQuestionGenerator(categoryService,Question.SPANISH); List questions = capitalQuestionGenerator.getQuestions(); Assertions.assertFalse(questions.isEmpty()); @@ -106,7 +106,7 @@ public void testCapitalQuestionsGenerator(){ @Test @Order(5) - public void testContinentQuestionsGenerator(){ + public void testContinentQuestionsGenerator() throws InterruptedException { ContinentQuestionGeneration continentQuestionGenerator=new ContinentQuestionGeneration(categoryService,Question.SPANISH); List questions = continentQuestionGenerator.getQuestions(); Assertions.assertFalse(questions.isEmpty()); @@ -1199,7 +1199,7 @@ private JSONObject parseJsonResponse(HttpResponse response) throws JSONE /** * Inserts some sample questions into the database */ - private void insertSomeQuestions() { + private void insertSomeQuestions() throws InterruptedException { List qs = new ContinentQuestionGeneration(categoryService, Question.SPANISH).getQuestions(); qs.forEach(questionService::addNewQuestion); }