Skip to content

Commit 0b9f7ec

Browse files
committed
Add more tests
1 parent 2a9afc7 commit 0b9f7ec

File tree

4 files changed

+100
-32
lines changed

4 files changed

+100
-32
lines changed

src/main/java/org/openpodcastapi/opa/advice/GlobalExceptionHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
public class GlobalExceptionHandler {
2222
@ExceptionHandler(EntityNotFoundException.class)
2323
@ResponseStatus(HttpStatus.NOT_FOUND)
24-
public ResponseEntity<String> handleEntityNotFoundException(EntityNotFoundException e) {
25-
return ResponseEntity.badRequest().body(e.getMessage());
24+
public ResponseEntity<String> handleEntityNotFoundException(EntityNotFoundException error) {
25+
log.debug("{}", error.getMessage());
26+
return ResponseEntity.notFound().build();
2627
}
2728

2829
@ExceptionHandler(DataIntegrityViolationException.class)

src/main/java/org/openpodcastapi/opa/subscription/SubscriptionService.java

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,31 @@ public class SubscriptionService {
2626

2727
/// Fetches an existing repository from the database or creates a new one if none is found
2828
///
29-
/// @param dto the [SubscriptionDTO.SubscriptionCreateDTO] containing the subscriptionEntity data
29+
/// @param dto the [SubscriptionDTO.SubscriptionCreateDTO] containing the subscription data
3030
/// @return the fetched or created [SubscriptionEntity]
3131
protected SubscriptionEntity fetchOrCreateSubscription(SubscriptionDTO.SubscriptionCreateDTO dto) {
3232
UUID feedUuid = UUID.fromString(dto.uuid());
3333
return subscriptionRepository
3434
.findByUuid(feedUuid)
3535
.orElseGet(() -> {
36-
log.debug("Creating new subscriptionEntity with UUID {}", dto.uuid());
36+
log.debug("Creating new subscription with UUID {}", dto.uuid());
3737
return subscriptionRepository.save(subscriptionMapper.toEntity(dto));
3838
});
3939
}
4040

41-
/// Fetches a single subscriptionEntity for an authenticated userEntity, if it exists
41+
/// Fetches a single subscription for an authenticated userEntity, if it exists
4242
///
43-
/// @param subscriptionUuid the UUID of the subscriptionEntity
44-
/// @param userId the database ID of the userEntity
45-
/// @return a [SubscriptionDTO.UserSubscriptionDTO] of the userEntity subscriptionEntity
43+
/// @param subscriptionUuid the UUID of the subscription
44+
/// @param userId the database ID of the user
45+
/// @return a [SubscriptionDTO.UserSubscriptionDTO] of the user subscription
4646
/// @throws EntityNotFoundException if no entry is found
4747
@Transactional(readOnly = true)
4848
public SubscriptionDTO.UserSubscriptionDTO getUserSubscriptionBySubscriptionUuid(UUID subscriptionUuid, Long userId) {
49-
log.debug("Fetching subscriptionEntity {} for userEntity {}", subscriptionUuid, userId);
49+
log.debug("Fetching subscription {} for userEntity {}", subscriptionUuid, userId);
5050
UserSubscriptionEntity subscription = userSubscriptionRepository.findByUserIdAndSubscriptionUuid(userId, subscriptionUuid)
51-
.orElseThrow(() -> new EntityNotFoundException("subscriptionEntity not found for userEntity"));
51+
.orElseThrow(() -> new EntityNotFoundException("subscription not found for userEntity"));
5252

53-
log.debug("SubscriptionEntity {} for userEntity {} found", subscriptionUuid, userId);
53+
log.debug("Subscription {} for userEntity {} found", subscriptionUuid, userId);
5454
return userSubscriptionMapper.toDto(subscription);
5555
}
5656

@@ -65,29 +65,29 @@ public Page<SubscriptionDTO.UserSubscriptionDTO> getAllSubscriptionsForUser(Long
6565
.map(userSubscriptionMapper::toDto);
6666
}
6767

68-
/// Gets all active subscriptions for the authenticated userEntity
68+
/// Gets all active subscriptions for the authenticated user
6969
///
70-
/// @param userId the database ID of the authenticated userEntity
70+
/// @param userId the database ID of the authenticated user
7171
/// @return a paginated set of [SubscriptionDTO.UserSubscriptionDTO] objects
7272
@Transactional(readOnly = true)
7373
public Page<SubscriptionDTO.UserSubscriptionDTO> getAllActiveSubscriptionsForUser(Long userId, Pageable pageable) {
7474
log.debug("Fetching all active subscriptions for {}", userId);
7575
return userSubscriptionRepository.findAllByUserIdAndIsSubscribedTrue(userId, pageable).map(userSubscriptionMapper::toDto);
7676
}
7777

78-
/// Persists a new userEntity subscriptionEntity to the database
79-
/// If an existing entry is found for the userEntity and subscriptionEntity, the `isSubscribed` property is set to `true`
78+
/// Persists a new user subscription to the database
79+
/// If an existing entry is found for the user and subscription, the `isSubscribed` property is set to `true`
8080
///
81-
/// @param subscriptionEntity the target subscriptionEntity
82-
/// @param userId the ID of the target userEntity
83-
/// @return a [SubscriptionDTO.UserSubscriptionDTO] representation of the subscriptionEntity link
84-
/// @throws EntityNotFoundException if no matching userEntity is found
81+
/// @param subscriptionEntity the target [SubscriptionEntity]
82+
/// @param userId the ID of the target user
83+
/// @return a [SubscriptionDTO.UserSubscriptionDTO] representation of the subscription link
84+
/// @throws EntityNotFoundException if no matching user is found
8585
protected SubscriptionDTO.UserSubscriptionDTO persistUserSubscription(SubscriptionEntity subscriptionEntity, Long userId) {
8686
UserEntity userEntity = userRepository.findById(userId).orElseThrow(() -> new EntityNotFoundException("userEntity not found"));
8787
log.debug("{}", userEntity);
8888

8989
UserSubscriptionEntity newSubscription = userSubscriptionRepository.findByUserIdAndSubscriptionUuid(userId, subscriptionEntity.getUuid()).orElseGet(() -> {
90-
log.debug("Creating new userEntity subscriptionEntity for userEntity {} and subscriptionEntity {}", userId, subscriptionEntity.getUuid());
90+
log.debug("Creating new subscription for user {} and subscription {}", userId, subscriptionEntity.getUuid());
9191
UserSubscriptionEntity createdSubscription = new UserSubscriptionEntity();
9292
createdSubscription.setIsSubscribed(true);
9393
createdSubscription.setUser(userEntity);
@@ -99,10 +99,10 @@ protected SubscriptionDTO.UserSubscriptionDTO persistUserSubscription(Subscripti
9999
return userSubscriptionMapper.toDto(userSubscriptionRepository.save(newSubscription));
100100
}
101101

102-
/// Creates UserSubscriptionEntity links in bulk. If the SubscriptionEntity isn't already in the system, this is added before the userEntity is subscribed.
102+
/// Creates [UserSubscriptionEntity] links in bulk. If the [SubscriptionEntity] isn't already in the system, this is added before the user is subscribed.
103103
///
104104
/// @param requests a list of [SubscriptionDTO.SubscriptionCreateDTO] objects to create
105-
/// @param userId the ID of the requesting userEntity
105+
/// @param userId the ID of the requesting user
106106
/// @return a [SubscriptionDTO.BulkSubscriptionResponseDTO] DTO containing a list of successes and failures
107107
@Transactional
108108
public SubscriptionDTO.BulkSubscriptionResponseDTO addSubscriptions(List<SubscriptionDTO.SubscriptionCreateDTO> requests, Long userId) {
@@ -113,7 +113,7 @@ public SubscriptionDTO.BulkSubscriptionResponseDTO addSubscriptions(List<Subscri
113113

114114
for (SubscriptionDTO.SubscriptionCreateDTO dto : requests) {
115115
try {
116-
// Fetch or create the subscriptionEntity object to subscribe the userEntity to
116+
// Fetch or create the subscription object to subscribe the user to
117117
SubscriptionEntity subscriptionEntity = this.fetchOrCreateSubscription(dto);
118118
log.debug("{}", subscriptionEntity);
119119
// If all is successful, persist the new UserSubscriptionEntity and add a UserSubscriptionDTO to the successes list
@@ -131,15 +131,15 @@ public SubscriptionDTO.BulkSubscriptionResponseDTO addSubscriptions(List<Subscri
131131
return new SubscriptionDTO.BulkSubscriptionResponseDTO(successes, failures);
132132
}
133133

134-
/// Updates the status of a subscriptionEntity for a given userEntity
134+
/// Updates the status of a subscription for a given user
135135
///
136-
/// @param feedUUID the UUID of the subscriptionEntity feed
137-
/// @param userId the ID of the userEntity
136+
/// @param feedUUID the UUID of the subscription feed
137+
/// @param userId the ID of the user
138138
/// @return a [SubscriptionDTO.UserSubscriptionDTO] containing the updated object
139139
@Transactional
140140
public SubscriptionDTO.UserSubscriptionDTO unsubscribeUserFromFeed(UUID feedUUID, Long userId) {
141141
UserSubscriptionEntity subscription = userSubscriptionRepository.findByUserIdAndSubscriptionUuid(userId, feedUUID)
142-
.orElseThrow(() -> new EntityNotFoundException("no subscriptionEntity found"));
142+
.orElseThrow(() -> new EntityNotFoundException("no subscription found"));
143143

144144
subscription.setIsSubscribed(false);
145145
return userSubscriptionMapper.toDto(userSubscriptionRepository.save(subscription));

src/test/java/org/openpodcastapi/opa/subscriptions/SubscriptionEntityRestControllerTest.java

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.openpodcastapi.opa.subscriptions;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import jakarta.persistence.EntityNotFoundException;
45
import org.junit.jupiter.api.BeforeEach;
56
import org.junit.jupiter.api.Test;
67
import org.openpodcastapi.opa.security.TokenService;
@@ -17,7 +18,6 @@
1718
import org.springframework.data.domain.PageImpl;
1819
import org.springframework.data.domain.Pageable;
1920
import org.springframework.http.MediaType;
20-
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
2121
import org.springframework.restdocs.payload.JsonFieldType;
2222
import org.springframework.security.test.context.support.WithMockUser;
2323
import org.springframework.test.context.ActiveProfiles;
@@ -85,6 +85,14 @@ void setup() {
8585
accessToken = tokenService.generateAccessToken(mockUser);
8686
}
8787

88+
@Test
89+
void getAllSubscriptionsForAnonymous_shouldReturn401() throws Exception {
90+
mockMvc.perform(get("/api/v1/subscriptions")
91+
.param("page", "0")
92+
.param("size", "20"))
93+
.andExpect(status().isUnauthorized());
94+
}
95+
8896
@Test
8997
@WithMockUser(username = "user")
9098
void getAllSubscriptionsForUser_shouldReturnSubscriptions() throws Exception {
@@ -150,6 +158,24 @@ void getAllSubscriptionsForUser_shouldIncludeUnsubscribedWhenRequested() throws
150158
preprocessResponse(prettyPrint())));
151159
}
152160

161+
@Test
162+
void getSubscriptionByUuidForAnonymous_shouldReturnUnauthorized() throws Exception {
163+
mockMvc.perform(get("/api/v1/subscriptions/{uuid}", UUID.randomUUID())
164+
.param("page", "0")
165+
.param("size", "20"))
166+
.andExpect(status().isUnauthorized());
167+
}
168+
169+
@Test
170+
@WithMockUser(username = "test")
171+
void getNonexistentSubscription_shouldReturnNotFound() throws Exception {
172+
when(subscriptionService.getUserSubscriptionBySubscriptionUuid(any(UUID.class), anyLong()))
173+
.thenThrow(new EntityNotFoundException());
174+
175+
mockMvc.perform(get("/api/v1/subscriptions/{uuid}", UUID.randomUUID())
176+
.header("Authorization", "Bearer " + accessToken))
177+
.andExpect(status().isNotFound());
178+
}
153179

154180
@Test
155181
@WithMockUser(username = "user")
@@ -182,6 +208,22 @@ void getSubscriptionByUuid_shouldReturnSubscription() throws Exception {
182208
));
183209
}
184210

211+
@Test
212+
void createUserSubscriptionWithAnonymousUser_shouldReturnUnauthorized() throws Exception {
213+
mockMvc.perform(post("/api/v1/subscriptions")
214+
.contentType(MediaType.APPLICATION_JSON))
215+
.andExpect(status().isUnauthorized());
216+
}
217+
218+
@Test
219+
@WithMockUser(username = "user")
220+
void createUserSubscriptionsWithoutBody_shouldReturnBadRequest() throws Exception {
221+
mockMvc.perform(post("/api/v1/subscriptions")
222+
.header("Authorization", "Bearer " + accessToken)
223+
.contentType(MediaType.APPLICATION_JSON))
224+
.andExpect(status().isBadRequest());
225+
}
226+
185227
@Test
186228
@WithMockUser(username = "user")
187229
void createUserSubscriptions_shouldReturnMixedResponse() throws Exception {
@@ -307,9 +349,28 @@ void createUserSubscription_shouldReturnFailure() throws Exception {
307349
)));
308350
}
309351

352+
@Test
353+
void unsubscribingWithAnonymousUser_shouldReturnUnauthorized() throws Exception {
354+
mockMvc.perform(post("/api/v1/subscriptions/{uuid}/unsubscribe", UUID.randomUUID())
355+
.accept(MediaType.APPLICATION_JSON))
356+
.andExpect(status().isUnauthorized());
357+
}
358+
359+
@Test
360+
@WithMockUser(username = "user")
361+
void unsubscribingNonexistentEntity_shouldReturnNotFound() throws Exception {
362+
when(subscriptionService.unsubscribeUserFromFeed(any(UUID.class), anyLong()))
363+
.thenThrow(new EntityNotFoundException());
364+
365+
mockMvc.perform(post("/api/v1/subscriptions/{uuid}/unsubscribe", UUID.randomUUID())
366+
.header("Authorization", "Bearer " + accessToken)
367+
.accept(MediaType.APPLICATION_JSON))
368+
.andExpect(status().isNotFound());
369+
}
370+
310371
@Test
311372
@WithMockUser(username = "user")
312-
void updateSubscriptionStatus_shouldReturnUpdatedSubscription() throws Exception {
373+
void unsubscribe_shouldReturnUpdatedSubscription() throws Exception {
313374
UUID subscriptionUuid = UUID.randomUUID();
314375
boolean newStatus = false;
315376

@@ -325,7 +386,7 @@ void updateSubscriptionStatus_shouldReturnUpdatedSubscription() throws Exception
325386
.thenReturn(updatedSubscription);
326387

327388
// Act & Assert
328-
mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/subscriptions/{uuid}/unsubscribe", subscriptionUuid)
389+
mockMvc.perform(post("/api/v1/subscriptions/{uuid}/unsubscribe", subscriptionUuid)
329390
.header("Authorization", "Bearer " + accessToken)
330391
.accept(MediaType.APPLICATION_JSON))
331392
.andExpect(status().isOk())

src/test/java/org/openpodcastapi/opa/user/UserRestControllerTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ class UserRestControllerTest {
5454
@MockitoBean
5555
private UserService userService;
5656

57+
@Test
58+
void getAllUsers_shouldReturn401_forAnonymousUser() throws Exception {
59+
mockMvc.perform(get("/api/v1/users")
60+
.accept(MediaType.APPLICATION_JSON))
61+
.andExpect(status().isUnauthorized());
62+
}
63+
5764
@Test
5865
@WithMockUser(username = "admin", roles = {"USER", "ADMIN"})
5966
void getAllUsers_shouldReturn200_andList() throws Exception {
@@ -130,7 +137,6 @@ void getAllUsers_shouldReturn200_andList() throws Exception {
130137

131138
@Test
132139
@WithMockUser(username = "user", roles = "USER")
133-
// Mock the userEntity with a "USER" role
134140
void getAllUsers_shouldReturn403_forUserRole() throws Exception {
135141
UserEntity mockUser = UserEntity
136142
.builder()
@@ -152,7 +158,7 @@ void getAllUsers_shouldReturn403_forUserRole() throws Exception {
152158
.accept(MediaType.APPLICATION_JSON)
153159
.param("page", "0")
154160
.param("size", "20"))
155-
.andExpect(status().isForbidden()) // Expect 403 for the userEntity role
161+
.andExpect(status().isForbidden())
156162
.andDo(document("users-list",
157163
preprocessRequest(prettyPrint()),
158164
preprocessResponse(prettyPrint()),

0 commit comments

Comments
 (0)