Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

statistics update #314

Merged
merged 36 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0671f94
chore: removed unused images
Toto-hitori Apr 28, 2024
eed63e1
docs: added prometheus and grafana images
Toto-hitori Apr 28, 2024
3171c45
docs: prepared for performance efficiency
Toto-hitori Apr 28, 2024
3c41922
doc/Documentation for Gatling
sergioqfeg1 Apr 28, 2024
5f0ea70
docs: added enter
Toto-hitori Apr 28, 2024
d07c6ab
docs: updated actuator.png
Toto-hitori Apr 28, 2024
bab3260
Feat: Added new question
UO283615 Apr 28, 2024
1d7617a
Feat: Added new question (with the calls)
UO283615 Apr 28, 2024
6e2e709
docs: test machine
Toto-hitori Apr 28, 2024
fe37443
Fix: Solved the string of the questions (copypaste bad ☹)
UO283615 Apr 28, 2024
5d00180
Fix: Added diversity to the question
UO283615 Apr 28, 2024
43e6fe5
docs: security and mantainability
Toto-hitori Apr 28, 2024
4015426
fix: fixed gonzalo a link
Toto-hitori Apr 28, 2024
5de5a30
Merge pull request #309 from Arquisoft/feat/questionPublisherDate
Toto-hitori Apr 28, 2024
c4e769a
Merge pull request #310 from Arquisoft/docs/documentation-fixes
UO283615 Apr 28, 2024
a5c29fe
Added architecture decissions
UO283615 Apr 28, 2024
18d9ba9
docs: Added the abbreviation as it is sometimes refered like that in …
UO283615 Apr 28, 2024
c71e788
chore: removed e2e from pipeline
Toto-hitori Apr 28, 2024
2abcb24
Merge remote-tracking branch 'origin/develop' into develop
Toto-hitori Apr 28, 2024
7644fbd
docs: added technical risks
UO283615 Apr 28, 2024
a21fa9b
Fix: Removed unused variable
UO283615 Apr 28, 2024
b35faf2
Merge pull request #311 from Arquisoft/docs/diegoRevisited
GOLASOOO Apr 28, 2024
77fc5b3
Merge pull request #312 from Arquisoft/fix/fixCode
GOLASOOO Apr 28, 2024
5ffcafe
feat: modified top ten so it has number of played games into account
Toto-hitori Apr 28, 2024
16ca59e
test: top 10 v2
Toto-hitori Apr 28, 2024
e60e6e0
feat: size for username and password
Toto-hitori Apr 28, 2024
cb68c40
feat: new user statistics
Toto-hitori Apr 28, 2024
f7b5f89
feat: replaced table for a list
jjgancfer Apr 28, 2024
8386efe
chore: add a minimum width for the panel
jjgancfer Apr 28, 2024
7182771
test: removed user statistics
Toto-hitori Apr 28, 2024
ba15f01
feat: KIWIIIIIIIIIII
Toto-hitori Apr 28, 2024
a25056e
chore: change width prop
jjgancfer Apr 28, 2024
bb80033
Merge branch 'feat/statistics-top' of github.com:Arquisoft/wiq_en2b i…
jjgancfer Apr 28, 2024
7132d41
feat: max width
Toto-hitori Apr 28, 2024
755d5f4
Merge pull request #313 from Arquisoft/feat/statistics-top
GOLASOOO Apr 28, 2024
536ef1c
Merge branch 'master' into develop
Toto-hitori Apr 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 7 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,9 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
e2e-tests:
needs: [ unit-tests ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm --prefix webapp install
- run: npm --prefix webapp run build
# - run: npm --prefix webapp run test:e2e
docker-push-api:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
needs: [ unit-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
Expand All @@ -67,7 +56,7 @@ jobs:
SSL_PASSWORD
docker-push-prometheus:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
needs: [ unit-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
Expand All @@ -80,7 +69,7 @@ jobs:
workdir: api/monitoring/prometheus
docker-push-grafana:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
needs: [ unit-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
Expand All @@ -93,7 +82,7 @@ jobs:
workdir: api/monitoring/grafana
docker-push-reverse-proxy:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
needs: [ unit-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
Expand All @@ -109,11 +98,9 @@ jobs:
permissions:
contents: read
packages: write
needs: [ e2e-tests ]
needs: [ unit-tests ]
steps:

- uses: actions/checkout@v4

- name: Create .env file
run: echo "REACT_APP_API_ENDPOINT=https://${{secrets.APP_DOMAIN}}:8443" > webapp/.env

Expand All @@ -132,7 +119,7 @@ jobs:
REACT_APP_API_ENDPOINT
docker-push-question-generator:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
needs: [ unit-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
Expand Down Expand Up @@ -175,4 +162,4 @@ jobs:
echo "SSL_PASSWORD=${{ secrets.SSL_PASSWORD }}" >> .env
docker compose --profile prod down
docker compose --profile prod up -d --pull always
docker image prune -f
docker image prune -f
3 changes: 3 additions & 0 deletions api/src/main/java/lab/en2b/quizapi/auth/dtos/RegisterDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
Expand All @@ -19,10 +20,12 @@ public class RegisterDto {
private String email;
@NonNull
@NotBlank
@Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters")
@Schema(description = "Username used for registering", example = "example user" )
private String username;
@NonNull
@NotBlank
@Size(min = 6, max = 20, message = "Password must be between 6 and 20 characters")
@Schema(description = "Password used for registering", example = "password" )
private String password;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package lab.en2b.quizapi.questions.answer;

public enum AnswerCategory {
CAPITAL_CITY, COUNTRY, SONG, STADIUM, BALLON_DOR, GAMES_PUBLISHER, PAINTING, WTPOKEMON, GAMES_COUNTRY, GAMES_GENRE, BASKETBALL_VENUE, COUNTRY_FLAG
CAPITAL_CITY, COUNTRY, SONG, STADIUM, BALLON_DOR, GAMES_PUBLISHER, PAINTING, WTPOKEMON, GAMES_COUNTRY, GAMES_GENRE, BASKETBALL_VENUE, COUNTRY_FLAG, GAMES_RELEASE
}

Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ public class QuestionHelper {

private QuestionHelper(){} // To hide the implicit public constructor as this is static only

private static final int MAX_DISTRACTORS = 3;

public static List<Answer> getDistractors(AnswerRepository answerRepository, Question question){
return answerRepository.findDistractors(question.getAnswerCategory().toString(), question.getLanguage(), question.getCorrectAnswer().getText(), MAX_DISTRACTORS);
return answerRepository.findDistractors(question.getAnswerCategory().toString(), question.getLanguage(), question.getCorrectAnswer().getText(), 3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@
import org.springframework.data.jpa.repository.Query;

import java.util.Optional;
import java.util.List;

public interface StatisticsRepository extends JpaRepository<Statistics, Long> {

@Query(value = "SELECT * FROM Statistics WHERE user_id = ?1", nativeQuery = true)
Optional<Statistics> findByUserId(Long userId);

//Query that gets the top ten ordered by statistics -> statistics.getCorrectRate() * statistics.getTotal() / 9L
@Query(value = "SELECT *, \n" +
" CASE \n" +
" WHEN total = 0 THEN 0 \n" +
" ELSE (correct * 100.0 / NULLIF(total, 0)) * total \n" +
" END AS points \n" +
"FROM Statistics \n" +
"ORDER BY points DESC LIMIT 10 ", nativeQuery = true)
List<Statistics> findTopTen();

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ public StatisticsResponseDto getStatisticsForUser(Authentication authentication)
}

public List<StatisticsResponseDto> getTopTenStatistics(){
List<Statistics> all = new ArrayList<>(statisticsRepository.findAll());
all.sort(Comparator.comparing(Statistics::getCorrectRate).reversed());
List<Statistics> topTen = all.stream().limit(10).toList();
return topTen.stream().map(statisticsResponseDtoMapper).collect(Collectors.toList());
return statisticsRepository.findTopTen().stream().map(statisticsResponseDtoMapper).collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ public class StatisticsResponseDto {
private Long wrong;
private Long total;
private UserResponseDto user;
@JsonProperty("correct_rate")
private Long correctRate;
@JsonProperty("percentage")
private Long percentage;
@JsonProperty("points")
private Long points;
@JsonProperty("finished_games")
private Long finishedGames;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ public StatisticsResponseDto apply(Statistics statistics) {
.right(statistics.getCorrect())
.wrong(statistics.getWrong())
.total(statistics.getTotal())
.percentage(statistics.getCorrectRate())
.user(userResponseDtoMapper.apply(statistics.getUser()))
.correctRate(statistics.getCorrectRate())
.points(statistics.getCorrectRate() * statistics.getTotal() )
.finishedGames(statistics.getFinishedGames())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ public void setUp(){
.right(5L)
.wrong(5L)
.total(10L)
.correctRate(50L)
.percentage(50L)
.points(500L)
.user(defaultUserResponseDto)
.finishedGames(1L)
.build();
Expand All @@ -105,7 +106,8 @@ public void setUp(){
.right(7L)
.wrong(3L)
.total(10L)
.correctRate(70L)
.points(700L)
.percentage(70L)
.user(defaultUserResponseDto)
.finishedGames(1L)
.build();
Expand All @@ -131,7 +133,8 @@ public void getStatisticsForUserTestEmpty(){
.right(0L)
.wrong(0L)
.total(0L)
.correctRate(0L)
.points(0L)
.percentage(0L)
.finishedGames(0L)
.user(defaultUserResponseDto).build()
, result);
Expand All @@ -152,7 +155,7 @@ public void getCorrectRateTotalZero(){

@Test
public void getTopTenStatisticsTestWhenThereAreNotTen(){
when(statisticsRepository.findAll()).thenReturn(List.of(defaultStatistics2, defaultStatistics1));
when(statisticsRepository.findTopTen()).thenReturn(List.of(defaultStatistics2, defaultStatistics1));
List<StatisticsResponseDto> result = statisticsService.getTopTenStatistics();
Assertions.assertEquals(List.of(defaultStatisticsResponseDto2,defaultStatisticsResponseDto1), result);
}
Expand All @@ -172,11 +175,12 @@ public void getTopTenStatisticsTestWhenThereAreNotTenAndAreEqual(){
.right(5L)
.wrong(5L)
.total(10L)
.correctRate(50L)
.points(500L)
.percentage(50L)
.user(defaultUserResponseDto)
.finishedGames(1L)
.build();
when(statisticsRepository.findAll()).thenReturn(List.of(defaultStatistics1, defaultStatistics3));
when(statisticsRepository.findTopTen()).thenReturn(List.of(defaultStatistics1, defaultStatistics3));
List<StatisticsResponseDto> result = statisticsService.getTopTenStatistics();
Assertions.assertEquals(List.of(defaultStatisticsResponseDto1,defaultStatisticsResponseDto3), result);
}
Expand Down
Binary file removed docs/images/05_building_blocks-EN.png
Binary file not shown.
Binary file not shown.
Binary file removed docs/images/ContainerDiagram.png
Binary file not shown.
Binary file added docs/images/Gatling_10000_users.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/Gatling_1000_users.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/Gatling_100_users.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/Gatling_1_user.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/TechnicalContextDiagram.png
Binary file not shown.
Binary file added docs/images/actuator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/images/arc42-logo.png
Binary file not shown.
Binary file added docs/images/codescene-general.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/grafana.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/prometheus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/src/01_introduction_and_goals.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ See the complete functional requirements in the xref:#section-annex[Annex] of th
| Reliability | The system should be reliable in generating questions from Wikidata, ensuring that questions are accurate and diverse. The system shall handle user registrations, logins, and game data storage without errors.
| Availability | The system shall be available 99% of the time a user tries to access it.
| Maintainability | The system shall be designed and implemented in a way that facilitates easy maintenance and updates.
| Performance efficiency | The system shall deliver optimal performance, ensuring responsive interactions for users. The automatic generation of questions from Wikidata and the real-time gameplay shall be efficient. The system shall handle N concurrent users.
| Security | The system shall prioritize user data security. It shall implement robust authentication mechanisms for user registration and login. The API access points for user information and generated questions shall be secured with proper authorization.
| Performance efficiency | The system shall deliver optimal performance, ensuring responsive interactions for users. The automatic generation of questions from Wikidata and the real-time gameplay shall be efficient. The system shall handle 1000 concurrent users.
| Security | The system shall prioritize user data security. It shall implement robust authentication mechanisms for user registration and login. The API access points for user information and generated questions shall be secured with proper authorization.
| Usability | The system shall provide a user-friendly interface, making it easy for users to register, log in, and play the game. The system learning time for a user should be less than 4 hours.
| Compatibility | The system shall be compatible with various web browsers and devices, ensuring a seamless experience for users regardless of their choice of platform. It has to be well-optimized for different screen sizes and functionalities.
|===
Expand Down
8 changes: 7 additions & 1 deletion docs/src/09_architecture_decisions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ During the application development process, decisions had to be made as issues e

|Architecture of the Question Generator
|It has been decided to implement the QG in an independent module so it is only run once and it is not generating questions at real time, this way, we are not dependent on wikidata for having our application available.

|Template method pattern
|We chose to apply our software design knowledge and generate the questions following a template method in Java. This allows us to create new questions easily and without duplicating too much code.

|Use of JPA in the Question Generator
|We used JPA in favor of JDBC as when tables are related in a DB, JPA makes it easier to write into the DB.
|===

If needed, a more descriptive record can be seen link:https://github.com/Arquisoft/wiq_en2b/wiki[here].
If needed, more details are given in the link:https://github.com/Arquisoft/wiq_en2b/wiki[wiki].

92 changes: 63 additions & 29 deletions docs/src/10_quality_requirements.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,10 @@ ifndef::imagesdir[:imagesdir: ../images]
=== Quality Tree
This quality tree is a high-level overview of the quality goals and requirements. The Quality tree uses "quality" as a root while the rest of the quality categories will be displayed as branches.

[plantuml,"Quality Tree",png]
[plantuml,"Quality Tree",png,align="center"]
----
@startuml
title Quality attributes
agent Quality
agent Security
agent Reliability
agent Transferability
agent Usability
agent "Performance Efficiency"
agent Maintainability
agent Availability
agent Compatibility
agent "Functional Suitability"

Quality --- Security
Quality --- Reliability
Quality --- Transferability
Quality --- Usability
Quality --- "Performance Efficiency"
Quality --- Maintainability
Quality --- Availability
Quality --- Compatibility
Quality --- "Functional Suitability"
@enduml
include::../diagrams/10_Quality_Tree.puml[]
----

=== Quality Scenarios
To obtain a measurable system response to stimulus corresponding to the various quality branches outlined in the mindmap, we will use quality scenarios. Scenarios make quality requirements concrete and allow to more easily measure or decide whether they are fulfilled.

Expand All @@ -42,17 +19,74 @@ To obtain a measurable system response to stimulus corresponding to the various
| Functional suitability | Users shall be able to register, log in, play the quiz, and access historical data without encountering errors or glitches. | High, Medium
| Reliability | The system shall reliably generate accurate and diverse questions from Wikidata. User registrations, logins, and game data storage shall be handled without errors. | High, Medium
| Availability | The system shall be available 99% of the time when a user attempts to access it. | High, High
| Performance efficiency | The system shall deliver optimal performance, ensuring responsive interactions for users. It shall efficiently generate questions from Wikidata and handle real-time gameplay with up to N concurrent users. | High, High
| Performance efficiency | The system shall deliver optimal performance, ensuring responsive interactions for users. It shall efficiently generate questions from Wikidata and handle real-time gameplay with up to 1000 concurrent users. | High, High
| Usability | The system shall provide a user-friendly interface, allowing users to register, log in, and play the game with a learning time of less than 4 hours. | High, Medium
| Security | User data shall be securely handled. Robust authentication mechanisms shall be in place for user registration and login. API access points for user information and generated questions shall be secured with proper authorization. | Medium, High
| Compatibility | The system shall be compatible with various web browsers and devices, providing a seamless experience for users regardless of their choice of platform. It shall be well-optimized for different screen sizes and functionalities. | High, Medium
| Transferability | The system shall allow for easy transfer of user data and game-related information through its APIs. | Medium, High
| Testability | The unit tests shall have at least 80% coverage. | High, Medium
| Monitoring | The system shall have monitoring in place to track the performance and availability of the system. | High, Medium
|===
==== Change Scenarios
[options="header",cols="1,3,1"]
|===
|Quality attribute|Scenario|Priority
| Maintainability | The system shall be designed and implemented in a way that allows for easy maintenance and updates. | High, Medium
| Modifiability | The system shall be designed and implemented in a way that allows for easy maintenance and updates. | High, Medium
| Maintainability | The code of the system shall be well-documented, and modular, allowing for efficient troubleshooting and modifications. | High, Medium
|===
|===

==== Implementation

===== Performance efficiency
The tests were done with a 2 core and 4 GB of memory system.
This system's efficiency has been measured with Gatling. For the script that we used, a user already created, logged in and played a full game. After that, the user clicked to look the statistics.
The scripts were run a total of 4 times. One with 1 user, other with 100 users, another one with 1000 users and finally one with 10000 users.
The results of this scripts show that response times are reasonable up until 1000 users. Having 10000 users playing a game at the same time make a lot of failures.
Here are the results.

**1 user:**

image::Gatling_1_user.png[align="center", title="Gatling results with 1 user"]

**100 users:**

image::Gatling_100_users.png[align="center", title="Gatling results with 100 user"]

**1000 users:**

image::Gatling_1000_users.png[align="center", title="Gatling results with 1000 user"]

**10000 users:**

image::Gatling_10000_users.png[align="center", title="Gatling results with 10000 user"]

===== Security
The system is secured using Spring Security. The user data is stored in a database and the passwords are hashed using BCrypt. The API access points are secured with proper authorization. HTTPS is used to encrypt the data in transit.

The system is also protected against SQL injection via using JPA repositories and prepared statements.

The system is also designed in such a way that prevents cheating, by limiting the options available for the user and doing all validation in the backend, such as checking if the answer is correct, preventing request forgery.

===== Testability

===== Monitoring
The system is monitored using Spring Boot Actuator and Prometheus. The monitoring data is visualized using Grafana.

The actuator is deployed in https://kiwiq.run.place:8443/actuator/prometheus.

image::actuator.png[align="center", title="Spring Boot Actuator"]

The Prometheus server is deployed in http://20.199.84.5:9090.

image::prometheus.png[align="center", title="Prometheus"]

The Grafana is deployed in http://20.199.84.5:9091. The Grafana dashboard is available at the following link with user [email protected] and password aswgrafana.

The dashboard used is: https://grafana.com/grafana/dashboards/6756-spring-boot-statistics/
Make sure to put kiwiq.run.place:8443 as the Instance and WIQ API as the application.

image::grafana.png[align="center", title="Graphana Spring Boot dashboard"]

===== Maintainability
In our CodeScene analysis we find that our knowledge distribution is well-balanced as well as a nice code health, excepting one hotspot on a test that is not relevant.

image::codescene-general.png[align="center", title="CodeScene general view"]
Loading