Skip to content

Commit 8825036

Browse files
authored
Create tests for User Functionalities (#25)
1 parent b5fd60f commit 8825036

File tree

13 files changed

+403
-9
lines changed

13 files changed

+403
-9
lines changed

src/main/java/com/app/botblend/contoller/UserController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public UserDto getCurrent() {
4242
)
4343
@PreAuthorize("hasRole('ADMIN')")
4444
@PostMapping("/register")
45+
@ResponseStatus(HttpStatus.CREATED)
4546
public UserDto register(@RequestBody @Valid UserRegisterRequestDto requestDto) {
4647
return userService.register(requestDto);
4748
}
@@ -52,7 +53,6 @@ public UserDto register(@RequestBody @Valid UserRegisterRequestDto requestDto) {
5253
)
5354
@PreAuthorize("hasRole('ADMIN')")
5455
@PutMapping
55-
@ResponseStatus(HttpStatus.CREATED)
5656
public UserDto update(@RequestBody @Valid UserRegisterRequestDto requestDto) {
5757
return userService.updateCurrentUser(requestDto);
5858
}

src/main/java/com/app/botblend/handlers/OpenAiMessageHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.app.botblend.client.openai.model.OpenAiMessage;
66
import com.app.botblend.client.telegram.MessageHandler;
77
import com.app.botblend.service.MessagePersistenceService;
8-
import feign.RetryableException;
8+
import feign.FeignException;
99
import lombok.RequiredArgsConstructor;
1010
import org.springframework.beans.factory.annotation.Value;
1111
import org.springframework.stereotype.Component;
@@ -60,7 +60,7 @@ private OpenAiMessage requestOpenaiMessage(OpenAiMessage request) {
6060
.choices().get(DEFAULT_CHOICE)
6161
.message();
6262

63-
} catch (RetryableException e) {
63+
} catch (FeignException e) {
6464
return OpenAiMessage.builder(
6565
OpenAiMessage.Role.SYSTEM,
6666
OVERLOADED_SERVER_MESSAGE)

src/main/java/com/app/botblend/model/Role.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
import jakarta.persistence.GenerationType;
99
import jakarta.persistence.Id;
1010
import jakarta.persistence.Table;
11+
import lombok.AllArgsConstructor;
1112
import lombok.Data;
13+
import lombok.NoArgsConstructor;
1214

1315
@Data
16+
@NoArgsConstructor
17+
@AllArgsConstructor
1418
@Entity
1519
@Table(name = "roles")
1620
public class Role {

src/main/java/com/app/botblend/model/User.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
import jakarta.persistence.Table;
1212
import java.util.Collection;
1313
import java.util.Set;
14+
import lombok.AllArgsConstructor;
1415
import lombok.Data;
1516
import lombok.EqualsAndHashCode;
17+
import lombok.NoArgsConstructor;
1618
import lombok.ToString;
1719
import org.hibernate.annotations.SQLDelete;
1820
import org.hibernate.annotations.Where;
@@ -21,6 +23,8 @@
2123
import org.springframework.security.core.userdetails.UserDetails;
2224

2325
@Data
26+
@NoArgsConstructor
27+
@AllArgsConstructor
2428
@Entity
2529
@SQLDelete(sql = "UPDATE users SET is_deleted = true WHERE id = ?")
2630
@Where(clause = "is_deleted = false")

src/test/java/com/app/botblend/contoller/ChatControllerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
class ChatControllerTest {
4141
protected static MockMvc mockMvc;
4242
private static final String INSERT_DATA_SCRIPT =
43-
"classpath:sqlscripts/InsertChatAndMessages.sql";
43+
"classpath:sqlscripts/insert-chats&messages.sql";
4444
private static final String DELETE_DATA_SCRIPT =
45-
"classpath:sqlscripts/DeleteChatAndMessages.sql";
45+
"classpath:sqlscripts/delete-chats&messages.sql";
4646
private static final LocalDateTime CREATED_AT = LocalDateTime.of(
4747
2023, 10, 10, 10, 0, 0
4848
);
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
package com.app.botblend.contoller;
2+
3+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
4+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
5+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
6+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
7+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
8+
9+
import com.app.botblend.dto.user.UserDto;
10+
import com.app.botblend.dto.user.UserRegisterRequestDto;
11+
import com.app.botblend.model.User;
12+
import com.app.botblend.utils.TestUserUtil;
13+
import com.fasterxml.jackson.core.type.TypeReference;
14+
import com.fasterxml.jackson.databind.ObjectMapper;
15+
import java.util.List;
16+
import java.util.stream.Stream;
17+
import lombok.SneakyThrows;
18+
import org.junit.jupiter.api.Assertions;
19+
import org.junit.jupiter.api.BeforeAll;
20+
import org.junit.jupiter.api.DisplayName;
21+
import org.junit.jupiter.api.DynamicTest;
22+
import org.junit.jupiter.api.Test;
23+
import org.junit.jupiter.api.TestFactory;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.boot.test.context.SpringBootTest;
26+
import org.springframework.http.MediaType;
27+
import org.springframework.mock.web.MockHttpServletResponse;
28+
import org.springframework.security.test.context.support.WithUserDetails;
29+
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
30+
import org.springframework.test.context.jdbc.Sql;
31+
import org.springframework.test.web.servlet.MockMvc;
32+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
33+
import org.springframework.web.context.WebApplicationContext;
34+
import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder;
35+
36+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
37+
class UserControllerTest {
38+
protected static MockMvc mockMvc;
39+
private static final User AUTHENTICATED_USER = TestUserUtil.USER_DATA.get(1L);
40+
private static final String AUTHENTICATED_USER_EMAIL = "bob@test.app";
41+
private static final List<UserRegisterRequestDto> USER_REGISTER_BAD_REQUEST = List.of(
42+
new UserRegisterRequestDto(
43+
"",
44+
"Pwd12345",
45+
"Pwd12345",
46+
"Bob",
47+
"Smith"
48+
),
49+
new UserRegisterRequestDto(
50+
"invalidemail",
51+
"Pwd12345",
52+
"Pwd12345",
53+
"Bob",
54+
"Smith"
55+
),
56+
new UserRegisterRequestDto(
57+
"user@example.com",
58+
null,
59+
"",
60+
"Bob",
61+
"Smith"
62+
),
63+
new UserRegisterRequestDto(
64+
"user@example.com",
65+
"Pwd12345",
66+
"Pwd123456",
67+
"Bob",
68+
"Smith"
69+
),
70+
new UserRegisterRequestDto(
71+
"user@example.com",
72+
"Pwd1",
73+
"Pwd1",
74+
"Bob",
75+
"Smith"
76+
),
77+
new UserRegisterRequestDto(
78+
"user@example.com",
79+
"VeryLongPassword",
80+
"VeryLongPassword",
81+
"Bob", "Smith"),
82+
new UserRegisterRequestDto(
83+
"user@example.com",
84+
"Pwd12345",
85+
"Pwd12345",
86+
"",
87+
"Smith"
88+
),
89+
new UserRegisterRequestDto(
90+
"user@example.com",
91+
"Pwd12345",
92+
"Pwd12345",
93+
"A",
94+
"Smith"
95+
),
96+
new UserRegisterRequestDto(
97+
"user@example.com",
98+
"Pwd12345",
99+
"Pwd12345",
100+
"Bob",
101+
""
102+
),
103+
new UserRegisterRequestDto(
104+
"user@example.com",
105+
"Pwd12345",
106+
"Pwd12345",
107+
"Bob",
108+
"S"
109+
)
110+
);
111+
112+
@Autowired
113+
private ObjectMapper objectMapper;
114+
115+
@BeforeAll
116+
static void beforeAll(@Autowired WebApplicationContext applicationContext) {
117+
mockMvc = MockMvcBuilders
118+
.webAppContextSetup(applicationContext)
119+
.apply(SecurityMockMvcConfigurers.springSecurity())
120+
.build();
121+
}
122+
123+
@SneakyThrows
124+
@Test
125+
@DisplayName("Get Current User: Admin User - Return UserDto")
126+
@WithUserDetails(AUTHENTICATED_USER_EMAIL)
127+
@Sql(scripts = {
128+
TestUserUtil.DELETE_USER_DATA,
129+
TestUserUtil.INSERT_USER_DATA
130+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
131+
void getCurrent_AdminUser_ReturnsUserDto() {
132+
UserDto expected = new UserDto(
133+
AUTHENTICATED_USER.getId(),
134+
AUTHENTICATED_USER.getEmail(),
135+
AUTHENTICATED_USER.getFirstName(),
136+
AUTHENTICATED_USER.getLastName()
137+
);
138+
139+
MockHttpServletResponse response = mockMvc.perform(get("/users")
140+
.contentType(MediaType.APPLICATION_JSON))
141+
.andExpect(status().isOk())
142+
.andReturn()
143+
.getResponse();
144+
145+
UserDto actual = objectMapper.readValue(
146+
response.getContentAsByteArray(),
147+
new TypeReference<>() {
148+
}
149+
);
150+
151+
Assertions.assertEquals(expected, actual);
152+
}
153+
154+
@SneakyThrows
155+
@Test
156+
@DisplayName("Get Current User: Non-Authenticated - Return 401 Forbidden")
157+
@Sql(scripts = {
158+
TestUserUtil.DELETE_USER_DATA,
159+
TestUserUtil.INSERT_USER_DATA
160+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
161+
void getCurrent_NonAuthenticated_Returns401() {
162+
mockMvc.perform(get("/users")
163+
.contentType(MediaType.APPLICATION_JSON))
164+
.andExpect(status().isUnauthorized());
165+
}
166+
167+
@SneakyThrows
168+
@Test
169+
@DisplayName("Register User: Valid Request - Return UserDto")
170+
@WithUserDetails(AUTHENTICATED_USER_EMAIL)
171+
@Sql(scripts = {
172+
TestUserUtil.DELETE_USER_DATA,
173+
TestUserUtil.INSERT_USER_DATA
174+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
175+
void register_ValidRequest_ReturnsUserDto() {
176+
UserRegisterRequestDto requestDto = new UserRegisterRequestDto(
177+
"frodo@test.app",
178+
TestUserUtil.PASSWORD,
179+
TestUserUtil.PASSWORD,
180+
"Frodo",
181+
"Baggins"
182+
);
183+
String request = objectMapper.writeValueAsString(requestDto);
184+
185+
UserDto expected = new UserDto(null,
186+
requestDto.email(),
187+
requestDto.firstName(),
188+
requestDto.lastName());
189+
190+
MockHttpServletResponse response = mockMvc.perform(
191+
post("/users/register")
192+
.content(request)
193+
.contentType(MediaType.APPLICATION_JSON))
194+
.andExpect(status().isCreated())
195+
.andReturn()
196+
.getResponse();
197+
198+
UserDto actual = objectMapper.readValue(
199+
response.getContentAsByteArray(),
200+
new TypeReference<>() {
201+
}
202+
);
203+
204+
EqualsBuilder.reflectionEquals(expected, actual, "id");
205+
}
206+
207+
@TestFactory
208+
@DisplayName("Register User: Invalid Request - Return 400 Bad Request")
209+
@WithUserDetails(AUTHENTICATED_USER_EMAIL)
210+
@Sql(scripts = {
211+
TestUserUtil.DELETE_USER_DATA,
212+
TestUserUtil.INSERT_USER_DATA
213+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
214+
Stream<DynamicTest> register_InvalidRequest_ReturnsHttp400BadRequest() {
215+
return USER_REGISTER_BAD_REQUEST.stream()
216+
.map(requestDto -> DynamicTest.dynamicTest(
217+
"Try register user: " + requestDto,
218+
() -> {
219+
String request = objectMapper.writeValueAsString(requestDto);
220+
mockMvc.perform(post("/users/register")
221+
.content(request)
222+
.contentType(MediaType.APPLICATION_JSON))
223+
.andExpect(status().isBadRequest());
224+
}
225+
));
226+
}
227+
228+
@SneakyThrows
229+
@Test
230+
@DisplayName("Update User: Admin User - Return 200 Ok")
231+
@WithUserDetails(AUTHENTICATED_USER_EMAIL)
232+
@Sql(scripts = {
233+
TestUserUtil.DELETE_USER_DATA,
234+
TestUserUtil.INSERT_USER_DATA
235+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
236+
void update_AdminUser_Returns200() {
237+
Long id = AUTHENTICATED_USER.getId();
238+
UserRegisterRequestDto requestDto = new UserRegisterRequestDto(
239+
AUTHENTICATED_USER_EMAIL,
240+
TestUserUtil.PASSWORD,
241+
TestUserUtil.PASSWORD,
242+
"UpdatedFirstName",
243+
"UpdatedLastName"
244+
);
245+
String request = objectMapper.writeValueAsString(requestDto);
246+
247+
UserDto expected = new UserDto(id,
248+
requestDto.email(),
249+
requestDto.firstName(),
250+
requestDto.lastName()
251+
);
252+
253+
MockHttpServletResponse response = mockMvc.perform(
254+
put("/users")
255+
.content(request)
256+
.contentType(MediaType.APPLICATION_JSON))
257+
.andExpect(status().isOk())
258+
.andReturn()
259+
.getResponse();
260+
261+
UserDto actual = objectMapper.readValue(
262+
response.getContentAsByteArray(),
263+
new TypeReference<>() {}
264+
);
265+
266+
Assertions.assertEquals(expected, actual);
267+
}
268+
269+
@SneakyThrows
270+
@Test
271+
@DisplayName("Delete User: Admin User - Return 204 No Content")
272+
@WithUserDetails(AUTHENTICATED_USER_EMAIL)
273+
@Sql(scripts = {
274+
TestUserUtil.DELETE_USER_DATA,
275+
TestUserUtil.INSERT_USER_DATA
276+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
277+
void delete_AdminUser_ReturnsHttp204NoContent() {
278+
long id = 2;
279+
mockMvc.perform(delete("/users/" + id))
280+
.andExpect(status().isNoContent());
281+
}
282+
283+
@SneakyThrows
284+
@Test
285+
@DisplayName("Delete User: Unauthorized User - Return 401")
286+
@Sql(scripts = {
287+
TestUserUtil.DELETE_USER_DATA,
288+
TestUserUtil.INSERT_USER_DATA
289+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
290+
void delete_UnauthorizedUser_Returns401() {
291+
long id = 1;
292+
mockMvc.perform(delete("/users/" + id))
293+
.andExpect(status().isUnauthorized());
294+
}
295+
296+
@SneakyThrows
297+
@Test
298+
@DisplayName("Delete User: User ID Not Found - Return 404 Not Found")
299+
@WithUserDetails(AUTHENTICATED_USER_EMAIL)
300+
@Sql(scripts = {
301+
TestUserUtil.DELETE_USER_DATA,
302+
TestUserUtil.INSERT_USER_DATA
303+
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
304+
void delete_UserIdNotFound_ReturnsHttp404NotFound() {
305+
long id = -99;
306+
mockMvc.perform(delete("/users/" + id))
307+
.andExpect(status().isNotFound());
308+
}
309+
}

0 commit comments

Comments
 (0)