diff --git a/Dockerfile b/Dockerfile index a6cac77..38df5e9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,9 +6,7 @@ COPY src /app/src COPY pom.xml /app WORKDIR /app -RUN mvn clean package -DskipTests -U \ - && rm -rf /root/.m2 \ - && rm -rf /app/src +RUN mvn clean package -DskipTests -U && rm -rf /root/.m2 && rm -rf /app/src # Run stage FROM eclipse-temurin:21-jre-alpine @@ -19,4 +17,4 @@ COPY --from=build /app/target/QualityLabPro-0.8.jar ./app.jar ENV SPRING_PROFILES_ACTIVE=prod \ SERVER_PORT=8080 -EXPOSE ${SERVER_PORT} \ No newline at end of file +EXPOSE ${SERVER_PORT} diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/configs/docs/SpringDocConfiguration.java b/src/main/java/leonardo/labutilities/qualitylabpro/configs/docs/SpringDocConfiguration.java index ba3731f..2a39cc1 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/configs/docs/SpringDocConfiguration.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/configs/docs/SpringDocConfiguration.java @@ -1,5 +1,7 @@ package leonardo.labutilities.qualitylabpro.configs.docs; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; @@ -7,24 +9,22 @@ import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.security.SecurityScheme; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; @Configuration @OpenAPIDefinition public class SpringDocConfiguration { @Bean - public OpenAPI customOpenAPI() { + OpenAPI customOpenAPI() { return new OpenAPI() .components(new Components().addSecuritySchemes("bearer-key", - new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer") - .bearerFormat("JWT"))) + new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer") + .bearerFormat("JWT"))) .info(new Info().title("QualityLab-Pro API").version("2.0").description( - "REST API for operations on analytical test specifications and internal " + - "control data") - .contact(new Contact().name("Leonardo Meireles") - .email("leomeireles55@hotmail.com")) - .license(new License().name("Apache 2.0") - .url("http://labutilities/api/license"))); + "REST API for operations on analytical test specifications and internal " + + "control data") + .contact(new Contact().name("Leonardo Meireles") + .email("leomeireles55@hotmail.com")) + .license(new License().name("Apache 2.0") + .url("http://labutilities/api/license"))); } } diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/configs/rest/WebConfig.java b/src/main/java/leonardo/labutilities/qualitylabpro/configs/rest/WebConfig.java index eacde2c..038ea84 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/configs/rest/WebConfig.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/configs/rest/WebConfig.java @@ -3,6 +3,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.format.FormatterRegistry; +import org.springframework.lang.NonNull; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import leonardo.labutilities.qualitylabpro.utils.components.StringToLocalDateTimeConverter; @@ -18,7 +19,7 @@ public WebConfig(StringToLocalDateTimeConverter dateTimeConverter) { } @Override - public void addFormatters(FormatterRegistry registry) { - registry.addConverter(dateTimeConverter); + public void addFormatters(@NonNull FormatterRegistry registry) { + registry.addConverter(this.dateTimeConverter); } } diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/CorsConfig.java b/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/CorsConfig.java index faae40c..afc6a6b 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/CorsConfig.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/CorsConfig.java @@ -12,8 +12,9 @@ public class CorsConfig implements WebMvcConfigurer { public void addCorsMappings(@NonNull CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:3000", "https://quality-lab-pro.vercel.app", - "https://www.lab-spec.systems", "https://lab-spec.systems", - "https://68.183.141.155", "https://leomeireles-dev.xyz") + + "https://www.lab-spec.systems", "https://lab-spec.systems") + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD") .allowedHeaders("*").exposedHeaders("Authorization").allowCredentials(true) .maxAge(3600); diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityConfiguration.java b/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityConfiguration.java index 5e112e3..acbc802 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityConfiguration.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityConfiguration.java @@ -1,6 +1,5 @@ package leonardo.labutilities.qualitylabpro.configs.security; -import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -15,77 +14,67 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import lombok.RequiredArgsConstructor; @Configuration @RequiredArgsConstructor @EnableWebSecurity public class SecurityConfiguration { - private final SecurityFilter securityFilter; + private final SecurityFilter securityFilter; - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - return http.csrf(AbstractHttpConfigurer::disable).cors(Customizer.withDefaults()) - .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(req -> { - // Public endpoints - req.requestMatchers(HttpMethod.POST, "/users/sign-in").permitAll(); - req.requestMatchers(HttpMethod.POST, "/users/sign-up").permitAll(); - req.requestMatchers(HttpMethod.POST, "/hematology-analytics/**").permitAll(); + @Bean + protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + return http.csrf(AbstractHttpConfigurer::disable).cors(Customizer.withDefaults()) + .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(req -> { + // Public endpoints + req.requestMatchers(HttpMethod.POST, "/users/sign-in").permitAll(); + req.requestMatchers(HttpMethod.POST, "/users/sign-up").permitAll(); + req.requestMatchers(HttpMethod.POST, "/hematology-analytics/**").permitAll(); - // Swagger/OpenAPI endpoints - req.requestMatchers("/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**") - .permitAll(); + // Swagger/OpenAPI endpoints + req.requestMatchers("/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**") + .permitAll(); - // Health check endpoints - req.requestMatchers("/actuator/**") - .permitAll(); + // Health check endpoints + req.requestMatchers("/actuator/**").permitAll(); - // Admin-only endpoints - req.requestMatchers(HttpMethod.DELETE, "/generic-analytics/**") - .hasRole("ADMIN"); - req.requestMatchers(HttpMethod.DELETE, "/biochemistry-analytics/**") - .hasRole("ADMIN"); - req.requestMatchers(HttpMethod.DELETE, "/hematology-analytics/**") - .hasRole("ADMIN"); - req.requestMatchers(HttpMethod.DELETE, "/coagulation-analytics/**") - .hasRole("ADMIN"); + // Admin-only endpoints + req.requestMatchers(HttpMethod.DELETE, "/generic-analytics/**").hasRole("ADMIN"); + req.requestMatchers(HttpMethod.DELETE, "/biochemistry-analytics/**") + .hasRole("ADMIN"); + req.requestMatchers(HttpMethod.DELETE, "/hematology-analytics/**").hasRole("ADMIN"); + req.requestMatchers(HttpMethod.DELETE, "/coagulation-analytics/**").hasRole("ADMIN"); - // Add PUT and PATCH restrictions for admin - req.requestMatchers(HttpMethod.PUT, "/generic-analytics/**").hasRole("ADMIN"); + // Add PUT and PATCH restrictions for admin + req.requestMatchers(HttpMethod.PUT, "/generic-analytics/**").hasRole("ADMIN"); - req.requestMatchers(HttpMethod.PUT, "/biochemistry-analytics/**") - .hasRole("ADMIN"); - req.requestMatchers(HttpMethod.PUT, "/hematology-analytics/**") - .hasRole("ADMIN"); - req.requestMatchers(HttpMethod.PUT, "/coagulation-analytics/**") - .hasRole("ADMIN"); + req.requestMatchers(HttpMethod.PUT, "/biochemistry-analytics/**").hasRole("ADMIN"); + req.requestMatchers(HttpMethod.PUT, "/hematology-analytics/**").hasRole("ADMIN"); + req.requestMatchers(HttpMethod.PUT, "/coagulation-analytics/**").hasRole("ADMIN"); - req.requestMatchers(HttpMethod.PATCH, "/generic-analytics/**").hasRole("ADMIN"); + req.requestMatchers(HttpMethod.PATCH, "/generic-analytics/**").hasRole("ADMIN"); - req.requestMatchers(HttpMethod.PATCH, "/biochemistry-analytics/**") - .hasRole("ADMIN"); - req.requestMatchers(HttpMethod.PATCH, "/hematology-analytics/**") - .hasRole("ADMIN"); - req.requestMatchers(HttpMethod.PATCH, "/coagulation-analytics/**") - .hasRole("ADMIN"); + req.requestMatchers(HttpMethod.PATCH, "/biochemistry-analytics/**").hasRole("ADMIN"); + req.requestMatchers(HttpMethod.PATCH, "/hematology-analytics/**").hasRole("ADMIN"); + req.requestMatchers(HttpMethod.PATCH, "/coagulation-analytics/**").hasRole("ADMIN"); - req.requestMatchers(HttpMethod.DELETE, "/users/**"); + req.requestMatchers(HttpMethod.DELETE, "/users/**"); - // All other endpoints require authentication - req.anyRequest().authenticated(); - }).addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class) - .build(); - } + // All other endpoints require authentication + req.anyRequest().authenticated(); + }).addFilterBefore(this.securityFilter, UsernamePasswordAuthenticationFilter.class) + .build(); + } - @Bean - public AuthenticationManager authMenager(AuthenticationConfiguration configuration) - throws Exception { - return configuration.getAuthenticationManager(); - } + @Bean + AuthenticationManager authMenager(AuthenticationConfiguration configuration) throws Exception { + return configuration.getAuthenticationManager(); + } - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } + @Bean + PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityFilter.java b/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityFilter.java index 65a0840..1247aa1 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityFilter.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/configs/security/SecurityFilter.java @@ -1,18 +1,17 @@ package leonardo.labutilities.qualitylabpro.configs.security; +import java.io.IOException; +import org.springframework.lang.NonNull; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import leonardo.labutilities.qualitylabpro.repositories.UserRepository; import leonardo.labutilities.qualitylabpro.services.authentication.TokenService; import lombok.RequiredArgsConstructor; -import org.springframework.lang.NonNull; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -import java.io.IOException; @Component @RequiredArgsConstructor @@ -23,15 +22,15 @@ public class SecurityFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(@NonNull HttpServletRequest request, - @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) + @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws IOException { try { - var tokenJWT = getToken(request); + var tokenJWT = this.getToken(request); if (tokenJWT != null) { - var subject = tokenService.getSubject(tokenJWT); - var users = userRepository.getReferenceByUsername(subject); + var subject = this.tokenService.getSubject(tokenJWT); + var users = this.userRepository.getReferenceOneByUsername(subject); var authentication = new UsernamePasswordAuthenticationToken(users, null, - users.getAuthorities()); + users.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticsRepository.java b/src/main/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticsRepository.java index 0aa156a..1337d84 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticsRepository.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticsRepository.java @@ -1,9 +1,7 @@ package leonardo.labutilities.qualitylabpro.repositories; -import jakarta.persistence.QueryHint; -import jakarta.transaction.Transactional; -import leonardo.labutilities.qualitylabpro.dtos.analytics.AnalyticsDTO; -import leonardo.labutilities.qualitylabpro.entities.Analytic; +import java.time.LocalDateTime; +import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -12,9 +10,10 @@ import org.springframework.data.jpa.repository.QueryHints; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; - -import java.time.LocalDateTime; -import java.util.List; +import jakarta.persistence.QueryHint; +import jakarta.transaction.Transactional; +import leonardo.labutilities.qualitylabpro.dtos.analytics.AnalyticsDTO; +import leonardo.labutilities.qualitylabpro.entities.Analytic; @Repository public interface AnalyticsRepository extends JpaRepository { @@ -65,6 +64,7 @@ List findByNameAndLevel(Pageable pageable, @Param("name") String name, List findByNameAndLevelAndLevelLot(Pageable pageable, @Param("name") String name, @Param("level") String level, @Param("levelLot") String levelLot); + @QueryHints({@QueryHint(name = "org.hibernate.readOnly", value = "true"), @QueryHint(name = "org.hibernate.fetchSize", value = "50"), @QueryHint(name = "org.hibernate.cacheable", value = "true")}) @@ -76,6 +76,8 @@ List findByNameAndLevelAndDateBetween(@Param("name") String name, @Param("level") String level, @Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate, Pageable pageable); + + // Fetch Analytics by Multiple Names and Date @QueryHints({@QueryHint(name = "org.hibernate.readOnly", value = "true"), @QueryHint(name = "org.hibernate.fetchSize", value = "50"), @@ -89,6 +91,7 @@ Page findByNameInAndLevelAndDateBetween(@Param("names") List { - UserDetails getReferenceByUsername(String username); + boolean existsByUsername(String name); + + boolean existsByEmail(String email); + + UserDetails getReferenceOneByUsername(String username); - User findByUsername(String username); + User findOneByUsername(String username); - User findByEmail(String email); + User findOneByEmail(String email); - User findByUsernameOrEmail(String username, String email); + User findOneByUsernameOrEmail(String username, String email); boolean existsByUsernameOrEmail(String username, String email); @@ -26,16 +30,12 @@ public interface UserRepository extends JpaRepository { @Transactional @Modifying - @Query("UPDATE users u SET u.password = ?2 WHERE u.username = ?1") + @Query("UPDATE users u SET u.password = :newPassword WHERE u.username = :username") void setPasswordWhereByUsername(String username, String newPassword); @Transactional @Modifying - @Query("UPDATE users u SET u.password = ?2 WHERE u.email = ?1") + @Query("UPDATE users u SET u.password = :newPassword WHERE u.email = :username") void setPasswordWhereByEmail(String email, String newPassword); - - boolean existsByUsername(String name); - - boolean existsByEmail(String email); } diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/authentication/AuthenticationService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/authentication/AuthenticationService.java index 585e6bb..42ccec2 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/services/authentication/AuthenticationService.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/authentication/AuthenticationService.java @@ -1,11 +1,11 @@ package leonardo.labutilities.qualitylabpro.services.authentication; -import leonardo.labutilities.qualitylabpro.repositories.UserRepository; -import lombok.RequiredArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; +import leonardo.labutilities.qualitylabpro.repositories.UserRepository; +import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Service @@ -15,7 +15,7 @@ public class AuthenticationService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - var user = userRepository.getReferenceByUsername(username); + var user = this.userRepository.getReferenceOneByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found: " + username); } diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java index f570af8..13b74e8 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java @@ -1,5 +1,10 @@ package leonardo.labutilities.qualitylabpro.services.users; +import java.time.LocalDateTime; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.stereotype.Service; import leonardo.labutilities.qualitylabpro.dtos.authentication.TokenJwtDTO; import leonardo.labutilities.qualitylabpro.dtos.email.EmailDTO; import leonardo.labutilities.qualitylabpro.dtos.email.RecoveryEmailDTO; @@ -13,12 +18,6 @@ import leonardo.labutilities.qualitylabpro.utils.exception.CustomGlobalErrorHandling; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; @RequiredArgsConstructor @Service @@ -41,45 +40,45 @@ private void sendRecoveryEmail(RecoveryEmailDTO recoveryEmailDTO) { Best regards, Your Team""", recoveryEmailDTO.temporaryPassword()); log.info("Sending recovery identifier to: {}", recoveryEmailDTO.email()); - emailService.sendPlainTextEmail(new EmailDTO(recoveryEmailDTO.email(), subject, message)); + this.emailService.sendPlainTextEmail(new EmailDTO(recoveryEmailDTO.email(), subject, message)); } public void recoverPassword(String username, String email) { - var user = userRepository.existsByUsernameAndEmail(username, email); + var user = this.userRepository.existsByUsernameAndEmail(username, email); if (!user) { throw new CustomGlobalErrorHandling.UserNotFoundException(); } - String temporaryPassword = passwordRecoveryTokenManager.generateTemporaryPassword(); - passwordRecoveryTokenManager.generateAndStoreToken(email, temporaryPassword); + String temporaryPassword = this.passwordRecoveryTokenManager.generateTemporaryPassword(); + this.passwordRecoveryTokenManager.generateAndStoreToken(email, temporaryPassword); - sendRecoveryEmail(new RecoveryEmailDTO(email, temporaryPassword)); + this.sendRecoveryEmail(new RecoveryEmailDTO(email, temporaryPassword)); } public void changePassword(String email, String temporaryPassword, String newPassword) { - if (!passwordRecoveryTokenManager.isRecoveryTokenValid(temporaryPassword, email)) { + if (!this.passwordRecoveryTokenManager.isRecoveryTokenValid(temporaryPassword, email)) { throw new CustomGlobalErrorHandling.RecoveryTokenInvalidException(); } - userRepository.setPasswordWhereByEmail(email, BCryptEncoderComponent.encrypt(newPassword)); + this.userRepository.setPasswordWhereByEmail(email, BCryptEncoderComponent.encrypt(newPassword)); } private TokenJwtDTO authenticateAndGenerateToken(User credential, String password) { try { final var authToken = new UsernamePasswordAuthenticationToken(credential.getUsername(), password); - final var auth = authenticationManager.authenticate(authToken); + final var auth = this.authenticationManager.authenticate(authToken); final var user = (User) auth.getPrincipal(); if (!auth.isAuthenticated()) { - emailService.notifyFailedUserLogin(user.getUsername(), user.getEmail(), + this.emailService.notifyFailedUserLogin(user.getUsername(), user.getEmail(), LocalDateTime.now()); throw new BadCredentialsException( "Authentication failed for user: " + credential.getUsername()); } - return tokenService.generateToken(user); + return this.tokenService.generateToken(user); } catch (BadCredentialsException e) { log.error("Authentication failed for user: {}", credential.getUsername(), e); @@ -89,7 +88,7 @@ private TokenJwtDTO authenticateAndGenerateToken(User credential, String passwor public User signUp(String username, String email, String password) { - if (userRepository.existsByUsernameOrEmail(email, email)) { + if (this.userRepository.existsByUsernameOrEmail(email, email)) { throw new CustomGlobalErrorHandling.UserAlreadyExistException(); } @@ -97,23 +96,23 @@ public User signUp(String username, String email, String password) { new User(username, BCryptEncoderComponent.encrypt(password), email, UserRoles.USER); try { - emailService.notifyUserSignup(user.getUsername(), user.getEmail(), LocalDateTime.now()); + this.emailService.notifyUserSignup(user.getUsername(), user.getEmail(), LocalDateTime.now()); } catch (Exception e) { log.error("Failed signup for user: {}. Exception: ", user.getEmail(), e); } - return userRepository.save(user); + return this.userRepository.save(user); } public TokenJwtDTO signIn(String identifier, String password) { try { - final var credential = userRepository.findByUsernameOrEmail(identifier, identifier); + final var credential = this.userRepository.findOneByUsernameOrEmail(identifier, identifier); if (credential == null) { throw new CustomGlobalErrorHandling.UserNotFoundException(); } - return authenticateAndGenerateToken(credential, password); + return this.authenticateAndGenerateToken(credential, password); } catch (Exception e) { log.error("Sign-in process failed for identifier: {}", identifier, e); @@ -122,7 +121,7 @@ public TokenJwtDTO signIn(String identifier, String password) { } public void updateUserPassword(String name, String email, String password, String newPassword) { - var oldPass = userRepository.getReferenceByUsernameAndEmail(name, email); + var oldPass = this.userRepository.getReferenceByUsernameAndEmail(name, email); boolean oldPasswordMatches = BCryptEncoderComponent.decrypt(password, oldPass.getPassword()); boolean newPasswordMatches = @@ -131,7 +130,7 @@ public void updateUserPassword(String name, String email, String password, Strin log.error("PasswordNotMatches. {}, {}", name, email); throw new CustomGlobalErrorHandling.PasswordNotMatchesException(); } else { - userRepository.setPasswordWhereByUsername(oldPass.getUsername(), + this.userRepository.setPasswordWhereByUsername(oldPass.getUsername(), BCryptEncoderComponent.encrypt(newPassword)); } } diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/StringToLocalDateTimeConverter.java b/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/StringToLocalDateTimeConverter.java index d327e25..761a939 100644 --- a/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/StringToLocalDateTimeConverter.java +++ b/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/StringToLocalDateTimeConverter.java @@ -1,8 +1,5 @@ package leonardo.labutilities.qualitylabpro.utils.components; -import org.springframework.core.convert.converter.Converter; -import org.springframework.stereotype.Component; - import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -10,6 +7,9 @@ import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.List; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; @Component public class StringToLocalDateTimeConverter implements Converter { @@ -21,8 +21,8 @@ public class StringToLocalDateTimeConverter implements Converter req // Public endpoints - .anyRequest().permitAll()); + .authorizeHttpRequests(req -> req // Public endpoints + .anyRequest().permitAll()); return http.build(); } diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticRepositoryTest.java b/src/test/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticRepositoryTest.java index a7e5d28..9af7295 100644 --- a/src/test/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticRepositoryTest.java +++ b/src/test/java/leonardo/labutilities/qualitylabpro/repositories/AnalyticRepositoryTest.java @@ -1,12 +1,11 @@ package leonardo.labutilities.qualitylabpro.repositories; -import jakarta.persistence.EntityManager; -import jakarta.persistence.Transient; -import leonardo.labutilities.qualitylabpro.dtos.analytics.AnalyticsDTO; -import leonardo.labutilities.qualitylabpro.entities.Analytic; -import leonardo.labutilities.qualitylabpro.utils.components.RulesValidatorComponent; -import leonardo.labutilities.qualitylabpro.utils.constants.AvailableBiochemistryAnalytics; -import leonardo.labutilities.qualitylabpro.utils.mappers.AnalyticMapper; +import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createSampleRecord; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.LocalDateTime; +import java.util.List; import org.flywaydb.core.Flyway; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -19,14 +18,13 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.test.context.ActiveProfiles; - -import java.time.LocalDateTime; -import java.util.List; - -import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createSampleRecord; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import jakarta.persistence.EntityManager; +import jakarta.persistence.Transient; +import leonardo.labutilities.qualitylabpro.dtos.analytics.AnalyticsDTO; +import leonardo.labutilities.qualitylabpro.entities.Analytic; +import leonardo.labutilities.qualitylabpro.utils.components.RulesValidatorComponent; +import leonardo.labutilities.qualitylabpro.utils.constants.AvailableBiochemistryAnalytics; +import leonardo.labutilities.qualitylabpro.utils.mappers.AnalyticMapper; @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @@ -54,19 +52,18 @@ static void setupDatabase(@Autowired Flyway flyway) { @BeforeEach void setupTestData() { - Analytic analytic = new Analytic(createSampleRecord(), rulesValidatorComponent); - repository.save(analytic); + Analytic analytic = new Analytic(createSampleRecord(), this.rulesValidatorComponent); + this.repository.save(analytic); } @Test() @DisplayName("Should find all Analytic by level") void testFindAllByLevel() { PageRequest pageable = PageRequest.of(0, 10); - List results = - repository - .findByNameInAndLevelAndDateBetween(ANALYTICS_NAME_LIST, "PCCC1", - testDate.minusDays(1), testDate.plusDays(1), pageable) - .stream().toList(); + List results = this.repository + .findByNameInAndLevelAndDateBetween(ANALYTICS_NAME_LIST, "PCCC1", + this.testDate.minusDays(1), this.testDate.plusDays(1), pageable) + .stream().toList(); assertThat(results).as("Results should not be empty for the given date range").isNotEmpty(); assertThat(results.getFirst().level()).as("Level should match PCCC1").isEqualTo("PCCC1"); } @@ -74,9 +71,9 @@ void testFindAllByLevel() { @Test @DisplayName("Should update Analytic.LevelLot by name,level and levelLot and return void") void testUpdateLevelLotByNameAndLevelAndLevelLot() { - repository.updateMeanByNameAndLevelAndLevelLot("ALB2", "PCCC1", "0774693", 3.25); - entityManager.clear(); - Analytic analytic = repository + this.repository.updateMeanByNameAndLevelAndLevelLot("ALB2", "PCCC1", "0774693", 3.25); + this.entityManager.clear(); + Analytic analytic = this.repository .findByNameAndLevelAndLevelLot(PageRequest.of(0, 10), "ALB2", "PCCC1", "0774693") .get(0); System.out.println(analytic.getMean()); @@ -86,15 +83,15 @@ void testUpdateLevelLotByNameAndLevelAndLevelLot() { @Test @DisplayName("Should find analytics by name when exists") void testExistsByName() { - assertTrue(repository.existsByName("ALB2")); - assertFalse(repository.existsByName("NONEXISTENT")); + assertTrue(this.repository.existsByName("ALB2")); + assertFalse(this.repository.existsByName("NONEXISTENT")); } @Test @DisplayName("Should find all analytics by name with pagination") void testFindAllByName() { PageRequest pageable = PageRequest.of(0, 10); - List results = repository.findByName("ALB2", pageable).stream() + List results = this.repository.findByName("ALB2", pageable).stream() .map(AnalyticMapper::toRecord).toList(); assertThat(results).isNotEmpty(); assertThat(results.getFirst().name()).isEqualTo("ALB2"); @@ -103,7 +100,8 @@ void testFindAllByName() { @Test @DisplayName("Should verify existence by date, level and name") void testExistsByDateAndLevelAndName() { - boolean exists = repository.existsByDateAndLevelAndName(testDate, "PCCC1", "ALB2"); + boolean exists = + this.repository.existsByDateAndLevelAndName(this.testDate, "PCCC1", "ALB2"); assertTrue(exists); } @@ -113,7 +111,7 @@ void testExistsByDateAndLevelAndName() { void testFindAllByNameAndLevel() { PageRequest pageable = PageRequest.of(0, 10); - List results = repository.findByNameAndLevel(pageable, "ALB2", "PCCC1") + List results = this.repository.findByNameAndLevel(pageable, "ALB2", "PCCC1") .stream().map(AnalyticMapper::toRecord).toList(); assertThat(results).isNotEmpty(); @@ -124,11 +122,11 @@ void testFindAllByNameAndLevel() { @Test @DisplayName("Should find all by names in list and date range") void testFindAllByNameInAndDateBetween() { - setupTestData(); + this.setupTestData(); List names = List.of("ALB2"); - Page results = repository.findByNameInAndDateBetween(names, - testDate.minusDays(1), testDate.plusDays(1), Pageable.unpaged()); + Page results = this.repository.findByNameInAndDateBetween(names, + this.testDate.minusDays(1), this.testDate.plusDays(1), Pageable.unpaged()); assertThat(results).isNotEmpty(); assertThat(results.getContent().get(0).name()).isEqualTo("ALB2"); @@ -137,11 +135,11 @@ void testFindAllByNameInAndDateBetween() { @Test @DisplayName("Should find all by names in list with pagination") void testFindAllByNameIn() { - setupTestData(); + this.setupTestData(); List names = List.of("ALB2"); PageRequest pageable = PageRequest.of(0, 10); - List results = repository.findByNameIn(names, pageable).stream() + List results = this.repository.findByNameIn(names, pageable).stream() .map(AnalyticMapper::toRecord).toList(); assertThat(results).isNotEmpty(); @@ -151,12 +149,12 @@ void testFindAllByNameIn() { @Test @DisplayName("Should find all by name, level and date range with pagination") void testFindAllByNameAndLevelAndDateBetween() { - setupTestData(); + this.setupTestData(); PageRequest pageable = PageRequest.of(0, 10); - List results = repository - .findByNameAndLevelAndDateBetween("ALB2", "PCCC1", testDate.minusDays(1), - testDate.plusDays(1), pageable) + List results = this.repository + .findByNameAndLevelAndDateBetween("ALB2", "PCCC1", this.testDate.minusDays(1), + this.testDate.plusDays(1), pageable) .stream().map(AnalyticMapper::toRecord).toList(); assertThat(results).isNotEmpty(); @@ -167,22 +165,22 @@ void testFindAllByNameAndLevelAndDateBetween() { @Test @DisplayName("Should find all by date range") void testFindAllByDateBetween() { - setupTestData(); - List results = - repository.findByDateBetween(testDate.minusDays(1), testDate.plusDays(1)).stream() - .map(AnalyticMapper::toRecord).toList(); + this.setupTestData(); + List results = this.repository + .findByDateBetween(this.testDate.minusDays(1), this.testDate.plusDays(1)).stream() + .map(AnalyticMapper::toRecord).toList(); assertThat(results).isNotEmpty(); } @Test @DisplayName("Should find all by name and date range grouped by level") void testFindAllByNameAndDateBetweenGroupByLevel() { - setupTestData(); + this.setupTestData(); PageRequest pageable = PageRequest.of(0, 10); - List results = repository - .findByNameAndDateBetweenGroupByLevel("ALB2", testDate.minusDays(1), - testDate.plusDays(1), pageable) + List results = this.repository + .findByNameAndDateBetweenGroupByLevel("ALB2", this.testDate.minusDays(1), + this.testDate.plusDays(1), pageable) .stream().map(AnalyticMapper::toRecord).toList(); assertThat(results).isNotEmpty(); diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/repositories/UserRepositoryTest.java b/src/test/java/leonardo/labutilities/qualitylabpro/repositories/UserRepositoryTest.java index 65b817f..75a4bb8 100644 --- a/src/test/java/leonardo/labutilities/qualitylabpro/repositories/UserRepositoryTest.java +++ b/src/test/java/leonardo/labutilities/qualitylabpro/repositories/UserRepositoryTest.java @@ -1,8 +1,6 @@ package leonardo.labutilities.qualitylabpro.repositories; -import leonardo.labutilities.qualitylabpro.entities.User; -import leonardo.labutilities.qualitylabpro.enums.UserRoles; -import leonardo.labutilities.qualitylabpro.utils.components.BCryptEncoderComponent; +import static org.assertj.core.api.Assertions.assertThat; import org.flywaydb.core.Flyway; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -12,8 +10,9 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; - -import static org.assertj.core.api.Assertions.assertThat; +import leonardo.labutilities.qualitylabpro.entities.User; +import leonardo.labutilities.qualitylabpro.enums.UserRoles; +import leonardo.labutilities.qualitylabpro.utils.components.BCryptEncoderComponent; @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @@ -33,15 +32,15 @@ public void setupTestData() { var user = new User("UserTest", BCryptEncoderComponent.encrypt("12345"), "leo@hotmail.com", UserRoles.USER); - userRepository.save(user); + this.userRepository.save(user); } @Test @DisplayName("return 200 when user is exists") @Transactional void findByLoginUserDataBaseIsUserExists() { - setupTestData(); - var userNotNull = userRepository.getReferenceByUsername("UserTest"); + this.setupTestData(); + var userNotNull = this.userRepository.getReferenceOneByUsername("UserTest"); assertThat(userNotNull).isNotNull(); } @@ -49,7 +48,7 @@ void findByLoginUserDataBaseIsUserExists() { @DisplayName("return null when user is empty") @Transactional void findByLoginUserDataBaseIsUserNotExists() { - var userEmpty = userRepository.getReferenceByUsername(""); + var userEmpty = this.userRepository.getReferenceOneByUsername(""); assertThat(userEmpty).isNull(); } @@ -57,18 +56,18 @@ void findByLoginUserDataBaseIsUserNotExists() { @DisplayName("return True when update passwords successful") @Transactional void setPasswordWhereByUsername() { - setupTestData(); + this.setupTestData(); String username = "UserTest"; String oldPassword = "12345"; String newPassword = "249195Leo@@"; var userWithOldPassword = - userRepository.getReferenceByUsernameAndEmail("UserTest", "leo@hotmail.com"); + this.userRepository.getReferenceByUsernameAndEmail("UserTest", "leo@hotmail.com"); - userRepository.setPasswordWhereByUsername(username, newPassword); + this.userRepository.setPasswordWhereByUsername(username, newPassword); var userWithNewPassword = - userRepository.getReferenceByUsernameAndEmail("UserTest", "leo@hotmail.com"); + this.userRepository.getReferenceByUsernameAndEmail("UserTest", "leo@hotmail.com"); assertThat(BCryptEncoderComponent.decrypt(oldPassword, userWithOldPassword.getPassword()) || BCryptEncoderComponent.decrypt(newPassword, userWithNewPassword.getPassword())) diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java b/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java index ec960d2..a954432 100644 --- a/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java +++ b/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java @@ -1,5 +1,32 @@ package leonardo.labutilities.qualitylabpro.services; +import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createDateRangeRecords; +import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createSampleRecord; +import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createSampleRecordList; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import leonardo.labutilities.qualitylabpro.dtos.analytics.AnalyticsDTO; import leonardo.labutilities.qualitylabpro.dtos.analytics.GroupedValuesByLevelDTO; import leonardo.labutilities.qualitylabpro.dtos.analytics.UpdateAnalyticsMeanDTO; @@ -11,23 +38,6 @@ import leonardo.labutilities.qualitylabpro.utils.components.RulesValidatorComponent; import leonardo.labutilities.qualitylabpro.utils.exception.CustomGlobalErrorHandling; import leonardo.labutilities.qualitylabpro.utils.mappers.AnalyticMapper; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; -import java.util.stream.Stream; - -import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class AnalyticHelperServiceTests { @@ -44,13 +54,14 @@ class AnalyticHelperServiceTests { @BeforeEach void setUp() { try (AutoCloseable closeable = MockitoAnnotations.openMocks(this)) { - analyticHelperService = new AbstractAnalyticHelperService(analyticsRepository, - emailService, controlRulesValidators) { + this.analyticHelperService = new AbstractAnalyticHelperService(this.analyticsRepository, + this.emailService, this.controlRulesValidators) { @Override public List findAnalyticsByNameAndLevel(Pageable pageable, String name, String level) { - return analyticsRepository.findByNameAndLevel(pageable, name, level).stream() + return AnalyticHelperServiceTests.this.analyticsRepository + .findByNameAndLevel(pageable, name, level).stream() .map(AnalyticMapper::toRecord).toList(); } @@ -58,7 +69,7 @@ public List findAnalyticsByNameAndLevel(Pageable pageable, public List findAnalyticsByNameAndLevelAndDate(String name, String level, LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) { - return analyticsRepository + return AnalyticHelperServiceTests.this.analyticsRepository .findByNameAndLevelAndDateBetween(name, level, dateStart, dateEnd, PageRequest.of(0, 200)) .stream().map(AnalyticMapper::toRecord).toList(); @@ -73,9 +84,9 @@ public List findAnalyticsByNameAndLevelAndDate(String name, @Test void updateAnalyticsMean() { var mockDto = new UpdateAnalyticsMeanDTO("Glucose", "PCCC1", "076587", 1.0); - analyticHelperService.updateAnalyticsMeanByNameAndLevelAndLevelLot(mockDto.name(), + this.analyticHelperService.updateAnalyticsMeanByNameAndLevelAndLevelLot(mockDto.name(), mockDto.level(), mockDto.levelLot(), mockDto.mean()); - verify(analyticsRepository).updateMeanByNameAndLevelAndLevelLot(mockDto.name(), + verify(this.analyticsRepository).updateMeanByNameAndLevelAndLevelLot(mockDto.name(), mockDto.level(), mockDto.levelLot(), mockDto.mean()); } @@ -100,32 +111,33 @@ void shouldValidateRulesProcessedByRulesValidatorComponent() { @Test void saveNewAnalyticsRecords_WithValidRecords_ShouldSaveSuccessfully() { List records = createSampleRecordList(); - when(analyticsRepository.existsByDateAndLevelAndName(any(), any(), any())) + when(this.analyticsRepository.existsByDateAndLevelAndName(any(), any(), any())) .thenReturn(false); - when(analyticsRepository.saveAll(any())) + when(this.analyticsRepository.saveAll(any())) .thenAnswer(invocation -> invocation.getArgument(0)); - assertDoesNotThrow(() -> analyticHelperService.saveNewAnalyticsRecords(records)); - verify(analyticsRepository, times(1)).saveAll(any()); + assertDoesNotThrow(() -> this.analyticHelperService.saveNewAnalyticsRecords(records)); + verify(this.analyticsRepository, times(1)).saveAll(any()); } @Test void saveNewAnalyticsRecords_WithDuplicateRecords_ShouldThrowException() { List records = createSampleRecordList(); - when(analyticsRepository.existsByDateAndLevelAndName(any(), any(), any())).thenReturn(true); + when(this.analyticsRepository.existsByDateAndLevelAndName(any(), any(), any())) + .thenReturn(true); assertThrows(CustomGlobalErrorHandling.DataIntegrityViolationException.class, - () -> analyticHelperService.saveNewAnalyticsRecords(records)); - verify(analyticsRepository, never()).saveAll(any()); + () -> this.analyticHelperService.saveNewAnalyticsRecords(records)); + verify(this.analyticsRepository, never()).saveAll(any()); } @Test void findById_WithValidId_ShouldReturnRecord() { Long id = 1L; Analytic analytic = new Analytic(); - when(analyticsRepository.findById(id)).thenReturn(Optional.of(analytic)); + when(this.analyticsRepository.findById(id)).thenReturn(Optional.of(analytic)); - Analytic result = AnalyticMapper.toEntity(analyticHelperService.findOneById(id)); + Analytic result = AnalyticMapper.toEntity(this.analyticHelperService.findOneById(id)); assertNotNull(result); assertEquals(analytic, result); @@ -134,10 +146,10 @@ void findById_WithValidId_ShouldReturnRecord() { @Test void findById_WithInvalidId_ShouldThrowException() { Long id = 999L; - when(analyticsRepository.findById(id)).thenReturn(Optional.empty()); + when(this.analyticsRepository.findById(id)).thenReturn(Optional.empty()); assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class, - () -> analyticHelperService.findOneById(id)); + () -> this.analyticHelperService.findOneById(id)); } @Test @@ -149,14 +161,14 @@ void findAnalyticsByNameAndLevel_WithFilters_ShouldReturnFilteredRecords() { .filter(r -> r.name().equals(name) && r.level().equals(level)).toList().stream() .map(AnalyticMapper::toEntity).toList(); - when(analyticsRepository.findByNameAndLevel(pageable, name, level)) + when(this.analyticsRepository.findByNameAndLevel(pageable, name, level)) .thenReturn(expectedRecords); List result = - analyticHelperService.findAnalyticsByNameAndLevel(pageable, name, level); + this.analyticHelperService.findAnalyticsByNameAndLevel(pageable, name, level); assertEquals(expectedRecords.size(), result.size()); - verify(analyticsRepository).findByNameAndLevel(pageable, name, level); + verify(this.analyticsRepository).findByNameAndLevel(pageable, name, level); } @Test @@ -168,11 +180,11 @@ void findAllAnalyticsByNameAndLevelAndDate_WithDateRange_ShouldReturnFilteredRec List expectedRecords = createDateRangeRecords().stream().map(AnalyticMapper::toEntity).toList(); - when(analyticsRepository.findByNameAndLevelAndDateBetween(eq(name), eq(level), + when(this.analyticsRepository.findByNameAndLevelAndDateBetween(eq(name), eq(level), eq(startDate), eq(endDate), any(Pageable.class))).thenReturn(expectedRecords); - List result = analyticHelperService.findAnalyticsByNameAndLevelAndDate(name, - level, startDate, endDate, null); + List result = this.analyticHelperService + .findAnalyticsByNameAndLevelAndDate(name, level, startDate, endDate, null); assertNotNull(result); assertEquals(expectedRecords.size(), result.size()); @@ -181,49 +193,49 @@ void findAllAnalyticsByNameAndLevelAndDate_WithDateRange_ShouldReturnFilteredRec @Test void deleteAnalyticsById_WithValidId_ShouldDelete() { Long id = 1L; - when(analyticsRepository.existsById(id)).thenReturn(true); - doNothing().when(analyticsRepository).deleteById(id); + when(this.analyticsRepository.existsById(id)).thenReturn(true); + doNothing().when(this.analyticsRepository).deleteById(id); - assertDoesNotThrow(() -> analyticHelperService.deleteAnalyticsById(id)); + assertDoesNotThrow(() -> this.analyticHelperService.deleteAnalyticsById(id)); - verify(analyticsRepository).deleteById(id); + verify(this.analyticsRepository).deleteById(id); } @Test void deleteAnalyticsById_WithInvalidId_ShouldThrowException() { Long id = 999L; - when(analyticsRepository.existsById(id)).thenReturn(false); + when(this.analyticsRepository.existsById(id)).thenReturn(false); assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class, - () -> analyticHelperService.deleteAnalyticsById(id)); - verify(analyticsRepository, never()).deleteById(id); + () -> this.analyticHelperService.deleteAnalyticsById(id)); + verify(this.analyticsRepository, never()).deleteById(id); } @Test void ensureNameExists_WithValidName_ShouldNotThrowException() { String name = "Glucose"; - when(analyticsRepository.existsByName(name.toUpperCase())).thenReturn(true); + when(this.analyticsRepository.existsByName(name.toUpperCase())).thenReturn(true); - assertDoesNotThrow(() -> analyticHelperService.ensureNameExists(name)); + assertDoesNotThrow(() -> this.analyticHelperService.ensureNameExists(name)); } @Test void ensureNameExists_WithInvalidName_ShouldThrowException() { String name = "NonExistentTest"; - when(analyticsRepository.existsByName(name.toUpperCase())).thenReturn(false); + when(this.analyticsRepository.existsByName(name.toUpperCase())).thenReturn(false); assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class, - () -> analyticHelperService.ensureNameExists(name)); + () -> this.analyticHelperService.ensureNameExists(name)); } @Test void ensureNameNotExists_WithInvalidName_ShouldThrowException() { String name = "Glucose"; - when(analyticsRepository.existsByName(name.toUpperCase())).thenReturn(false); + when(this.analyticsRepository.existsByName(name.toUpperCase())).thenReturn(false); CustomGlobalErrorHandling.ResourceNotFoundException exception = assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class, - () -> analyticHelperService.ensureNameExists(name)); + () -> this.analyticHelperService.ensureNameExists(name)); assertEquals("AnalyticsDTO by name not found", exception.getMessage()); } @@ -231,10 +243,10 @@ void ensureNameNotExists_WithInvalidName_ShouldThrowException() { @Test void isAnalyticsNonExistent_WithNonExistentRecord_ShouldReturnTrue() { AnalyticsDTO record = createSampleRecord(); - when(analyticsRepository.existsByDateAndLevelAndName(record.date(), record.level(), + when(this.analyticsRepository.existsByDateAndLevelAndName(record.date(), record.level(), record.name())).thenReturn(false); - boolean result = analyticHelperService.isAnalyticsNonExistent(record); + boolean result = this.analyticHelperService.isAnalyticsNonExistent(record); assertTrue(result); } @@ -242,10 +254,10 @@ void isAnalyticsNonExistent_WithNonExistentRecord_ShouldReturnTrue() { @Test void isAnalyticsNonExistent_WithExistentRecord_ShouldReturnFalse() { AnalyticsDTO record = createSampleRecord(); - when(analyticsRepository.existsByDateAndLevelAndName(record.date(), record.level(), + when(this.analyticsRepository.existsByDateAndLevelAndName(record.date(), record.level(), record.name())).thenReturn(true); - boolean result = analyticHelperService.isAnalyticsNonExistent(record); + boolean result = this.analyticHelperService.isAnalyticsNonExistent(record); assertFalse(result); } @@ -258,15 +270,15 @@ void findGroupedAnalyticsByLevel_WithValidInputs_ShouldReturnGroupedRecords() { List records = createSampleRecordList().stream().map(AnalyticMapper::toEntity).toList(); - when(analyticsRepository.findByNameAndDateBetweenGroupByLevel(eq(name), eq(startDate), + when(this.analyticsRepository.findByNameAndDateBetweenGroupByLevel(eq(name), eq(startDate), eq(endDate), any(Pageable.class))).thenReturn(records); - List result = analyticHelperService + List result = this.analyticHelperService .findGroupedAnalyticsByLevel(name, startDate, endDate, Pageable.unpaged()); assertNotNull(result); assertFalse(result.isEmpty()); - verify(analyticsRepository).findByNameAndDateBetweenGroupByLevel(eq(name), eq(startDate), - eq(endDate), any(Pageable.class)); + verify(this.analyticsRepository).findByNameAndDateBetweenGroupByLevel(eq(name), + eq(startDate), eq(endDate), any(Pageable.class)); } }