diff --git a/postify/pom.xml b/postify/pom.xml index 7cea5f7..e46cbe4 100644 --- a/postify/pom.xml +++ b/postify/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent 4.0.6 - + net.hackyourfuture.backend.week6 postify @@ -27,14 +27,21 @@ - 25 + 17 org.springframework.boot - spring-boot-starter-webmvc + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.boot + spring-boot-starter-webflux - org.postgresql postgresql @@ -45,11 +52,17 @@ lombok true + + io.github.cdimascio + java-dotenv + 5.2.2 + org.springframework.boot - spring-boot-starter-webmvc-test + spring-boot-starter-test test + @@ -58,12 +71,7 @@ org.springframework.boot spring-boot-maven-plugin - - - org.projectlombok - lombok - - + diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/PostifyApplication.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/PostifyApplication.java index aa5e99f..2241443 100644 --- a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/PostifyApplication.java +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/PostifyApplication.java @@ -1,5 +1,6 @@ package net.hackyourfuture.backend.week6.postify; +import io.github.cdimascio.dotenv.Dotenv; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -7,6 +8,13 @@ public class PostifyApplication { public static void main(String[] args) { + + Dotenv dotenv = Dotenv.load(); + + System.setProperty("DB_USERNAME", dotenv.get("DB_USERNAME")); + System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD")); + + SpringApplication.run(PostifyApplication.class, args); } diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/config/RestClientConfig.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/config/RestClientConfig.java new file mode 100644 index 0000000..8c6a38d --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/config/RestClientConfig.java @@ -0,0 +1,16 @@ +package net.hackyourfuture.backend.week6.postify.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestClient; + +@Configuration +public class RestClientConfig { + + @Bean + public RestClient lyricsRestClient() { + return RestClient.builder() + .baseUrl("https://api.lyrics.ovh/v1") + .build(); + } +} diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/controller/TrackLyricsController.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/controller/TrackLyricsController.java new file mode 100644 index 0000000..4fd4055 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/controller/TrackLyricsController.java @@ -0,0 +1,26 @@ + +package net.hackyourfuture.backend.week6.postify.controller; + +import net.hackyourfuture.backend.week6.postify.dto.TrackLyricsResponse; +import net.hackyourfuture.backend.week6.postify.service.TrackLyricsService; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/tracks") +public class TrackLyricsController { + + private final TrackLyricsService trackLyricsService; + + public TrackLyricsController( + TrackLyricsService trackLyricsService) { + + this.trackLyricsService = trackLyricsService; + } + + @GetMapping("/{id}/lyrics") + public TrackLyricsResponse getLyrics( + @PathVariable Long id) { + + return trackLyricsService.getLyrics(id); + } +} \ No newline at end of file diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/controller/UserStatisticsController.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/controller/UserStatisticsController.java new file mode 100644 index 0000000..732b1f8 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/controller/UserStatisticsController.java @@ -0,0 +1,32 @@ +package net.hackyourfuture.backend.week6.postify.controller; + + +import net.hackyourfuture.backend.week6.postify.model.UserStatisticsResponse; +import net.hackyourfuture.backend.week6.postify.service.UserStatisticsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/users") +public class UserStatisticsController { + + @Autowired + private UserStatisticsService service; + + @GetMapping("/{id}/statistics") + public ResponseEntity getStats(@PathVariable int id) { + UserStatisticsResponse stats = service.getStats(id); + + if (stats == null) { + return ResponseEntity.status(404).body("User not found"); + } + + return ResponseEntity.ok(stats); + } + } + diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/dto/LyricsApiResponse.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/dto/LyricsApiResponse.java new file mode 100644 index 0000000..8420798 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/dto/LyricsApiResponse.java @@ -0,0 +1,11 @@ +package net.hackyourfuture.backend.week6.postify.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class LyricsApiResponse { + + private String lyrics; +} diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/dto/TrackLyricsResponse.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/dto/TrackLyricsResponse.java new file mode 100644 index 0000000..b13d8d4 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/dto/TrackLyricsResponse.java @@ -0,0 +1,19 @@ +package net.hackyourfuture.backend.week6.postify.dto; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class TrackLyricsResponse { + private int trackId; + private String trackTitle; + private String artistName; + private String lyrics; + +} diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/GlobalExceptionHandler.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..b45e90f --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/GlobalExceptionHandler.java @@ -0,0 +1,34 @@ +package net.hackyourfuture.backend.week6.postify.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(TrackNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Map handleTrackNotFound( + TrackNotFoundException exception) { + + return Map.of( + "message", + exception.getMessage() + ); + } + + @ExceptionHandler(LyricsNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Map handleLyricsNotFound( + LyricsNotFoundException exception) { + + return Map.of( + "message", + exception.getMessage() + ); + } +} \ No newline at end of file diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/LyricsNotFoundException.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/LyricsNotFoundException.java new file mode 100644 index 0000000..cbd00f1 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/LyricsNotFoundException.java @@ -0,0 +1,13 @@ + +package net.hackyourfuture.backend.week6.postify.exception; + +public class LyricsNotFoundException extends RuntimeException { + + public LyricsNotFoundException(String artistName, String trackTitle) { + super("Lyrics not found for '" + trackTitle + "' by " + artistName); + } + +} + + + diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/TrackNotFoundException.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/TrackNotFoundException.java new file mode 100644 index 0000000..7b9c6b1 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/exception/TrackNotFoundException.java @@ -0,0 +1,7 @@ +package net.hackyourfuture.backend.week6.postify.exception; + +public class TrackNotFoundException extends RuntimeException { + public TrackNotFoundException(int trackId) { + super("Track with id " + trackId + " not found"); + } +} diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/model/UserStatisticsResponse.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/model/UserStatisticsResponse.java new file mode 100644 index 0000000..10a3a99 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/model/UserStatisticsResponse.java @@ -0,0 +1,36 @@ +package net.hackyourfuture.backend.week6.postify.model; + +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@JsonPropertyOrder({ + "userId", + "userName", + "userCountry", + "totalStreams", + "uniqueTracksStreamed", + "uniqueArtistsStreamed", + "favoriteGenre", + "totalListeningTimeSeconds" +}) +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class UserStatisticsResponse { + + public int userId; + public String userName; + public String userCountry; + public int totalStreams; + public int uniqueTracksStreamed; + public int uniqueArtistsStreamed; + public String favoriteGenre; + public int totalListeningTimeSeconds; + +} + + diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/repository/TrackRepository.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/repository/TrackRepository.java new file mode 100644 index 0000000..c86ef71 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/repository/TrackRepository.java @@ -0,0 +1,44 @@ +package net.hackyourfuture.backend.week6.postify.repository; + + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + + +@Repository +public class TrackRepository { + + private final JdbcTemplate jdbcTemplate; + + public TrackRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public Optional findTrackWithArtistsById(int trackId) { + String sql = """ + SELECT + t.track_id, + t.track_title, + a.artist_name + FROM tracks t + JOIN albums al ON t.album_id = al.album_id + JOIN artists a ON al.artist_id = a.artist_id + WHERE t.track_id = ? + """; + + return jdbcTemplate.query(sql, rs -> { + if (!rs.next()) { + return Optional.empty(); + } + return Optional.of(new TrackWithArtist( + rs.getInt("track_id"), + rs.getString("track_title"), + rs.getString("artist_name") + )); + + }, trackId); + } + public record TrackWithArtist(int trackId, String trackTitle, String artistName) {} +} diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/repository/UserStatisticsRepository.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/repository/UserStatisticsRepository.java new file mode 100644 index 0000000..e567487 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/repository/UserStatisticsRepository.java @@ -0,0 +1,60 @@ +package net.hackyourfuture.backend.week6.postify.repository; + +import net.hackyourfuture.backend.week6.postify.model.UserStatisticsResponse; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; + +@Repository +public class UserStatisticsRepository { + + @Autowired + private JdbcTemplate jdbc; + + public UserStatisticsResponse getUserStats(int userId) { + String sql = """ + SELECT + u.user_id AS user_id, + u.user_name AS user_name, + u.user_country AS user_country, + COUNT(s.stream_id) AS total_streams, + COUNT(DISTINCT t.track_id) AS unique_tracks, + COUNT(DISTINCT ar.artist_id) AS unique_artists, + ( + SELECT t2.genre + FROM streams s2 + JOIN tracks t2 ON s2.track_id = t2.track_id + JOIN albums al2 ON t2.album_id = al2.album_id + JOIN artists ar2 ON al2.artist_id = ar2.artist_id + WHERE s2.user_id = u.user_id + GROUP BY t2.genre + ORDER BY COUNT(*) DESC + LIMIT 1 + ) AS favorite_genre, + SUM(t.track_duration_s) AS total_listening_seconds + FROM users u + LEFT JOIN streams s ON u.user_id = s.user_id + LEFT JOIN tracks t ON s.track_id = t.track_id + LEFT JOIN albums al ON t.album_id = al.album_id + LEFT JOIN artists ar ON al.artist_id = ar.artist_id + WHERE u.user_id = ? + GROUP BY u.user_id, u.user_name, u.user_country + """; + + List result = jdbc.query(sql, (rs, rowNum) -> { + UserStatisticsResponse r = new UserStatisticsResponse(); + r.userId = rs.getInt("user_id"); + r.userName = rs.getString("user_name"); + r.userCountry = rs.getString("user_country"); + r.totalStreams = rs.getInt("total_streams"); + r.uniqueTracksStreamed = rs.getInt("unique_tracks"); + r.uniqueArtistsStreamed = rs.getInt("unique_artists"); + r.favoriteGenre = rs.getString("favorite_genre"); + r.totalListeningTimeSeconds = rs.getInt("total_listening_seconds"); + return r; + }, userId); + + return result.isEmpty() ? null : result.get(0); + } +} diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/service/TrackLyricsService.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/service/TrackLyricsService.java new file mode 100644 index 0000000..dae500d --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/service/TrackLyricsService.java @@ -0,0 +1,56 @@ +package net.hackyourfuture.backend.week6.postify.service; + +import net.hackyourfuture.backend.week6.postify.exception.LyricsNotFoundException; +import net.hackyourfuture.backend.week6.postify.exception.TrackNotFoundException; +import net.hackyourfuture.backend.week6.postify.dto.LyricsApiResponse; +import net.hackyourfuture.backend.week6.postify.dto.TrackLyricsResponse; +import net.hackyourfuture.backend.week6.postify.repository.TrackRepository; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClient; + +@Service +public class TrackLyricsService { + + private final TrackRepository trackRepository; + private final RestClient lyricsRestClient; + + public TrackLyricsService(TrackRepository trackRepository, + RestClient lyricsRestClient) { + this.trackRepository = trackRepository; + this.lyricsRestClient = lyricsRestClient; + } + + public TrackLyricsResponse getLyrics(Long trackId) { + + TrackRepository.TrackWithArtist track = + trackRepository.findTrackWithArtistsById(trackId.intValue()) + .orElseThrow(() -> + new TrackNotFoundException(trackId.intValue())); + + try { + + LyricsApiResponse lyricsResponse = + lyricsRestClient.get() + .uri("/{artist}/{title}", + track.artistName(), + track.trackTitle()) + .retrieve() + .body(LyricsApiResponse.class); + + return new TrackLyricsResponse( + track.trackId(), + track.trackTitle(), + track.artistName(), + lyricsResponse.getLyrics() + ); + + } catch (HttpClientErrorException.NotFound exception) { + + throw new LyricsNotFoundException( + track.artistName(), + track.trackTitle() + ); + } + } +} \ No newline at end of file diff --git a/postify/src/main/java/net/hackyourfuture/backend/week6/postify/service/UserStatisticsService.java b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/service/UserStatisticsService.java new file mode 100644 index 0000000..14b7e60 --- /dev/null +++ b/postify/src/main/java/net/hackyourfuture/backend/week6/postify/service/UserStatisticsService.java @@ -0,0 +1,18 @@ +package net.hackyourfuture.backend.week6.postify.service; + +import net.hackyourfuture.backend.week6.postify.model.UserStatisticsResponse; +import net.hackyourfuture.backend.week6.postify.repository.UserStatisticsRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UserStatisticsService { + + @Autowired + private UserStatisticsRepository repo; + + public UserStatisticsResponse getStats(int userId) { + return repo.getUserStats(userId); + } + +} \ No newline at end of file diff --git a/postify/src/main/resources/application.properties b/postify/src/main/resources/application.properties index 8f4842f..149ea04 100644 --- a/postify/src/main/resources/application.properties +++ b/postify/src/main/resources/application.properties @@ -1 +1,6 @@ spring.application.name=postify + +spring.datasource.url=jdbc:postgresql://localhost:5432/postify_db +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} +spring.datasource.driver-class-name=org.postgresql.Driver \ No newline at end of file diff --git a/postify/src/test/java/net/hackyourfuture/backend/week6/postify/controller/TrackLyricsControllerTest.java b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/controller/TrackLyricsControllerTest.java new file mode 100644 index 0000000..b3b6ef6 --- /dev/null +++ b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/controller/TrackLyricsControllerTest.java @@ -0,0 +1,90 @@ +package net.hackyourfuture.backend.week6.postify.controller; + +import net.hackyourfuture.backend.week6.postify.exception.GlobalExceptionHandler; +import net.hackyourfuture.backend.week6.postify.exception.LyricsNotFoundException; +import net.hackyourfuture.backend.week6.postify.exception.TrackNotFoundException; +import net.hackyourfuture.backend.week6.postify.dto.TrackLyricsResponse; +import net.hackyourfuture.backend.week6.postify.service.TrackLyricsService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +class TrackLyricsControllerTest { + + private MockMvc mockMvc; + + @Mock + private TrackLyricsService trackLyricsService; + + @InjectMocks + private TrackLyricsController trackLyricsController; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + + mockMvc = MockMvcBuilders + .standaloneSetup(trackLyricsController) + .setControllerAdvice(new GlobalExceptionHandler()) + .build(); + } + + @Test + void shouldReturnLyrics_whenTrackExistsAndLyricsAvailable() throws Exception { + + TrackLyricsResponse response = new TrackLyricsResponse( + 41, + "LUNCH", + "Billie Eilish", + "I'm doing good, I'm on some new shit..." + ); + + when(trackLyricsService.getLyrics(41L)) + .thenReturn(response); + + mockMvc.perform(get("/tracks/41/lyrics")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.trackId").value(41)) + .andExpect(jsonPath("$.trackTitle").value("LUNCH")) + .andExpect(jsonPath("$.artistName").value("Billie Eilish")) + .andExpect(jsonPath("$.lyrics") + .value("I'm doing good, I'm on some new shit...")); + } + + @Test + void shouldReturn404_whenTrackDoesNotExist() throws Exception { + + when(trackLyricsService.getLyrics(999L)) + .thenThrow(new TrackNotFoundException(999)); + + mockMvc.perform(get("/tracks/999/lyrics")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message") + .value("Track with id 999 not found")); + } + + @Test + void shouldReturn404_whenLyricsNotAvailable() throws Exception { + + when(trackLyricsService.getLyrics(83L)) + .thenThrow(new LyricsNotFoundException( + "Tyler the Creator", + "WUSYANAME" + )); + + mockMvc.perform(get("/tracks/83/lyrics")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message") + .value("Lyrics not found for 'WUSYANAME' by Tyler the Creator")); + } +} \ No newline at end of file diff --git a/postify/src/test/java/net/hackyourfuture/backend/week6/postify/controller/UserStatisticsControllerTest.java b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/controller/UserStatisticsControllerTest.java new file mode 100644 index 0000000..0b35692 --- /dev/null +++ b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/controller/UserStatisticsControllerTest.java @@ -0,0 +1,58 @@ +package net.hackyourfuture.backend.week6.postify.controller; + +import net.hackyourfuture.backend.week6.postify.model.UserStatisticsResponse; +import net.hackyourfuture.backend.week6.postify.service.UserStatisticsService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +class UserStatisticsControllerTest { + + private MockMvc mockMvc; + + @Mock + private UserStatisticsService userStatisticsService; + + @InjectMocks + private UserStatisticsController userStatisticsController; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(userStatisticsController).build(); + } + + @Test + void shouldReturnUserStats_whenUserExists() throws Exception { + UserStatisticsResponse mockResponse = new UserStatisticsResponse( + 1, "lena_v", "NL", 65, 34, 8, "Nederpop", 14021 + ); + + when(userStatisticsService.getStats(1)).thenReturn(mockResponse); + + mockMvc.perform(get("/users/1/statistics")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.userId").value(1)) + .andExpect(jsonPath("$.userName").value("lena_v")) + .andExpect(jsonPath("$.totalStreams").value(65)); + } + + @Test + void shouldReturn404_whenUserDoesNotExist() throws Exception { + when(userStatisticsService.getStats(999)).thenReturn(null); + + mockMvc.perform(get("/users/999/statistics")) + .andExpect(status().isNotFound()); + } +} + diff --git a/postify/src/test/java/net/hackyourfuture/backend/week6/postify/model/UserStatisticsResponseTest.java b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/model/UserStatisticsResponseTest.java new file mode 100644 index 0000000..5f172f2 --- /dev/null +++ b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/model/UserStatisticsResponseTest.java @@ -0,0 +1,21 @@ +package net.hackyourfuture.backend.week6.postify.model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UserStatisticsResponseTest { + + @Test + void shouldContainCorrectUserStatistics() { + UserStatisticsResponse response = new UserStatisticsResponse(); + + response.userId = 1; + response.userName = "Abraham"; + response.userCountry = "CA"; + + assertEquals(1, response.userId); + assertEquals("Abraham", response.userName); + assertEquals("CA", response.userCountry); + } +} diff --git a/postify/src/test/java/net/hackyourfuture/backend/week6/postify/repository/TrackRepositoryTest.java b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/repository/TrackRepositoryTest.java new file mode 100644 index 0000000..451c569 --- /dev/null +++ b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/repository/TrackRepositoryTest.java @@ -0,0 +1,4 @@ +package net.hackyourfuture.backend.week6.postify.repository; + +public class TrackRepositoryTest { +} diff --git a/postify/src/test/java/net/hackyourfuture/backend/week6/postify/repository/UserStatisticsRepositoryTest.java b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/repository/UserStatisticsRepositoryTest.java new file mode 100644 index 0000000..18b2bbf --- /dev/null +++ b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/repository/UserStatisticsRepositoryTest.java @@ -0,0 +1,4 @@ +package net.hackyourfuture.backend.week6.postify.repository; + +public class UserStatisticsRepositoryTest { +} diff --git a/postify/src/test/java/net/hackyourfuture/backend/week6/postify/service/UserStatisticsServiceTest.java b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/service/UserStatisticsServiceTest.java new file mode 100644 index 0000000..4c7a3f9 --- /dev/null +++ b/postify/src/test/java/net/hackyourfuture/backend/week6/postify/service/UserStatisticsServiceTest.java @@ -0,0 +1,4 @@ +package net.hackyourfuture.backend.week6.postify.service; + +public class UserStatisticsServiceTest { +}