Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4500b0d

Browse files
Security_part_11_3: add WireMockLoansControllerIT.java
1 parent aac837d commit 4500b0d

File tree

1 file changed

+308
-0
lines changed

1 file changed

+308
-0
lines changed
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
package me.oldboy.integration.controllers.api_wiremock_scenario;
2+
3+
import com.fasterxml.jackson.core.type.TypeReference;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
6+
import com.github.tomakehurst.wiremock.WireMockServer;
7+
import com.github.tomakehurst.wiremock.client.WireMock;
8+
import lombok.SneakyThrows;
9+
import me.oldboy.config.security_details.ClientDetailsService;
10+
import me.oldboy.config.test_data_source.TestContainerInit;
11+
import me.oldboy.dto.loan_dto.LoanCreateDto;
12+
import me.oldboy.dto.loan_dto.LoanReadDto;
13+
import me.oldboy.integration.annotation.IT;
14+
import me.oldboy.jwt_test_utils.JwtTestUtils;
15+
import me.oldboy.services.LoanService;
16+
import org.jose4j.jwk.JsonWebKeySet;
17+
import org.jose4j.jwk.RsaJsonWebKey;
18+
import org.jose4j.jwk.RsaJwkGenerator;
19+
import org.jose4j.jws.AlgorithmIdentifiers;
20+
import org.jose4j.lang.JoseException;
21+
import org.junit.jupiter.api.AfterEach;
22+
import org.junit.jupiter.api.BeforeEach;
23+
import org.junit.jupiter.api.Test;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.http.MediaType;
26+
import org.springframework.test.annotation.DirtiesContext;
27+
import org.springframework.test.web.servlet.MockMvc;
28+
import org.springframework.test.web.servlet.MvcResult;
29+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
30+
import org.springframework.web.context.WebApplicationContext;
31+
32+
import java.time.LocalDate;
33+
import java.util.HashMap;
34+
import java.util.List;
35+
import java.util.Map;
36+
37+
import static com.github.tomakehurst.wiremock.client.WireMock.*;
38+
import static me.oldboy.test_constant.TestConstantFields.EXIST_EMAIL;
39+
import static me.oldboy.test_constant.TestConstantFields.EXIST_EMAIL_WITH_READ_AUTH;
40+
import static org.assertj.core.api.Assertions.assertThat;
41+
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
42+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
43+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
44+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
45+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
46+
47+
@IT
48+
/*
49+
В нашем случае тесты проходя поодиночке или даже в комплексе под одним классом при параллельном
50+
запуске всех разом приводят к падению части из них. Spring Test кэширует контекст, что может
51+
привести к проблемам. Добавим аннотацию @DirtiesContext на уровне классов, чтобы принудительно
52+
пересоздавать контекст - это очень сильно замедлит выполнение тестов, но обеспечит изоляцию и
53+
прохождения всех тестов "разом", при одновременном запуске.
54+
*/
55+
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
56+
class WireMockLoansControllerIT extends TestContainerInit {
57+
58+
@Autowired
59+
private LoanService loanService;
60+
@Autowired
61+
private ClientDetailsService clientDetailsService;
62+
63+
@Autowired
64+
private WebApplicationContext webApplicationContext;
65+
private MockMvc mockMvc;
66+
private WireMockServer wireMockServer;
67+
private RsaJsonWebKey rsaJsonWebKey;
68+
private Map<String, Object> realmAccessClaimsAdmin;
69+
private Map<String, Object> realmAccessClaimsUser;
70+
71+
private Long testId, anotherId;
72+
private LoanCreateDto testLoanCreateDtoForOwner, testLoanCreateDtoToAnotherClient;
73+
private List<LoanCreateDto> testList;
74+
private ObjectMapper objectMapper;
75+
76+
@BeforeEach
77+
void setUp() throws JoseException {
78+
testId = 1L;
79+
anotherId = 3L;
80+
81+
objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
82+
83+
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
84+
.apply(springSecurity())
85+
.build();
86+
87+
testLoanCreateDtoForOwner = LoanCreateDto.builder()
88+
.clientId(testId)
89+
.startDate(LocalDate.of(2021, 04,05))
90+
.loanType("Plane")
91+
.totalLoan(350000)
92+
.amountPaid(65000)
93+
.outstandingAmount(210000)
94+
.createDate(LocalDate.of(2021, 03,05))
95+
.build();
96+
testLoanCreateDtoToAnotherClient = LoanCreateDto.builder()
97+
.clientId(anotherId)
98+
.startDate(LocalDate.of(2022, 11,12))
99+
.loanType("Castle")
100+
.totalLoan(1350000)
101+
.amountPaid(115000)
102+
.outstandingAmount(600000)
103+
.createDate(LocalDate.of(2022, 10,03))
104+
.build();
105+
106+
testList = List.of(testLoanCreateDtoForOwner, testLoanCreateDtoToAnotherClient);
107+
108+
/* Инициализация WireMock сервера */
109+
wireMockServer = new WireMockServer(8089); // Если установить 0, то порт будет генерироваться случайный
110+
wireMockServer.start();
111+
WireMock.configureFor("localhost", wireMockServer.port());
112+
113+
/* Генерация RSA ключа для JWT */
114+
if (rsaJsonWebKey == null) {
115+
rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
116+
rsaJsonWebKey.setKeyId("k1");
117+
rsaJsonWebKey.setAlgorithm(AlgorithmIdentifiers.RSA_USING_SHA256);
118+
rsaJsonWebKey.setUse("sig");
119+
}
120+
121+
/* Настройка WireMock заглушки JWKS endpoint-a */
122+
stubFor(WireMock.get(urlEqualTo("/auth/realms/test-realm/protocol/openid-connect/certs"))
123+
.willReturn(aResponse()
124+
.withHeader("Content-Type", "application/json")
125+
.withBody(new JsonWebKeySet(rsaJsonWebKey).toJson())));
126+
127+
String openidConfig = "{ " +
128+
"\"issuer\": \"http://localhost:" + wireMockServer.port() + "/auth/realms/test-realm\", " +
129+
"\"jwks_uri\": \"http://localhost:" + wireMockServer.port() + "/auth/realms/test-realm/protocol/openid-connect/certs\" }";
130+
131+
/* Настройка WireMock заглушки для .well-known/openid-configuration */
132+
stubFor(WireMock.get(urlEqualTo("/auth/realms/test-realm/.well-known/openid-configuration"))
133+
.willReturn(aResponse()
134+
.withHeader("Content-Type", "application/json")
135+
.withBody(openidConfig)));
136+
137+
realmAccessClaimsAdmin = new HashMap<>();
138+
realmAccessClaimsAdmin.put("roles", List.of("ROLE_READ", "ROLE_ADMIN"));
139+
140+
realmAccessClaimsUser = new HashMap<>();
141+
realmAccessClaimsUser.put("roles", List.of("ROLE_USER"));
142+
}
143+
144+
@AfterEach
145+
public void tearDown() {
146+
if (wireMockServer != null) {
147+
wireMockServer.resetAll();
148+
wireMockServer.stop();
149+
wireMockServer = null;
150+
}
151+
}
152+
153+
@Test
154+
@SneakyThrows
155+
void getLoanDetails_ShouldReturnDtoList_ForClientWithLoans_Test() {
156+
String jwt = JwtTestUtils.generateJWT(EXIST_EMAIL, rsaJsonWebKey, wireMockServer, realmAccessClaimsAdmin);
157+
158+
MvcResult result = mockMvc.perform(get("/api/myLoans")
159+
.header("Authorization", "Bearer " + jwt))
160+
.andExpect(status().isOk())
161+
.andReturn();
162+
163+
String strRes = result.getResponse().getContentAsString();
164+
List<LoanReadDto> loansListFromBase = new ObjectMapper()
165+
.registerModule(new JavaTimeModule())
166+
.readValue(strRes, new TypeReference<List<LoanReadDto>>() {});
167+
168+
assertThat(loansListFromBase.size()).isGreaterThan(0);
169+
}
170+
171+
@Test
172+
@SneakyThrows
173+
void getLoanDetails_ShouldReturnEmptyBody_IfClientHasNoLoans_Test() {
174+
String jwt = JwtTestUtils.generateJWT(EXIST_EMAIL_WITH_READ_AUTH, rsaJsonWebKey, wireMockServer, realmAccessClaimsUser);
175+
176+
mockMvc.perform(get("/api/myLoans")
177+
.header("Authorization", "Bearer " + jwt))
178+
.andExpect(status().is2xxSuccessful())
179+
.andExpect(content().string(""));
180+
}
181+
182+
@Test
183+
@SneakyThrows
184+
void getLoanDetails_ShouldReturnNotAuth_4xx_WithoutAuth_Test() {
185+
mockMvc.perform(get("/api/myLoans"))
186+
.andExpect(status().is4xxClientError())
187+
.andExpect(content().string(""));
188+
}
189+
190+
@Test
191+
@SneakyThrows
192+
void createLoan_ShouldReturnOk_AndRecordIdFromBase_Test() {
193+
String jwt = JwtTestUtils.generateJWT(EXIST_EMAIL, rsaJsonWebKey, wireMockServer, realmAccessClaimsAdmin);
194+
/* Подготовим данные для сохранения в БД*/
195+
String strLoanCreateDto = objectMapper.writeValueAsString(testLoanCreateDtoForOwner);
196+
197+
/* Делаем запрос на сохранение */
198+
MvcResult result = mockMvc.perform(post("/api/createLoan")
199+
.contentType(MediaType.APPLICATION_JSON)
200+
.content(strLoanCreateDto)
201+
.header("Authorization", "Bearer " + jwt))
202+
.andExpect(status().isOk())
203+
.andReturn();
204+
205+
/* "Парсим" ответ */
206+
String strRes = result.getResponse().getContentAsString();
207+
Long afterCreateLoanId = objectMapper.readValue(strRes, Long.class);
208+
209+
/* Сравниваем ожидание с результатом - ID последней записи будет больше последнего известного из БД - 8 */
210+
assertThat(afterCreateLoanId).isGreaterThan(8);
211+
}
212+
213+
/* Id аутентифицированного клиента и Id того на кого оформлен кредит не совпадает - сохранить нельзя */
214+
215+
@Test
216+
@SneakyThrows
217+
void createLoan_ShouldReturnBadRequest_TryToSaveNotYoursLoan_Test() {
218+
String jwt = JwtTestUtils.generateJWT(EXIST_EMAIL, rsaJsonWebKey, wireMockServer, realmAccessClaimsAdmin);
219+
/* Подготовим данные для сохранения в БД*/
220+
String strLoanCreateDto = objectMapper.writeValueAsString(testLoanCreateDtoToAnotherClient);
221+
222+
/* Делаем запрос на сохранение */
223+
mockMvc.perform(post("/api/createLoan")
224+
.header("Authorization", "Bearer " + jwt)
225+
.contentType(MediaType.APPLICATION_JSON)
226+
.content(strLoanCreateDto))
227+
.andExpect(status().isBadRequest())
228+
.andExpect(content().string(""));
229+
}
230+
231+
@Test
232+
@SneakyThrows
233+
void saveAllMyRequestLoan_ShouldReturnOk_AndSaveOnlyAuthOwnerLoans_Test() {
234+
String jwt = JwtTestUtils.generateJWT(EXIST_EMAIL, rsaJsonWebKey, wireMockServer, realmAccessClaimsAdmin);
235+
/* Получим количество записей в БД */
236+
List<LoanReadDto> loansList = loanService.findAll();
237+
Integer listSizeBefore = loansList.size();
238+
239+
/* Подготовим данные для сохранения в БД */
240+
String strList = objectMapper.writeValueAsString(testList);
241+
242+
/* Делаем запрос на сохранение */
243+
mockMvc.perform(post("/api/save-all-loans")
244+
.contentType(MediaType.APPLICATION_JSON)
245+
.content(strList)
246+
.header("Authorization", "Bearer " + jwt))
247+
.andExpect(status().isOk())
248+
.andExpect(content().string("Saved all loans!"));
249+
250+
/* Проверяем количество записей в БД после сохранения списка кредитов - больше на одну */
251+
Integer listSizeAfter = loanService.findAll().size();
252+
assertThat(listSizeAfter).isEqualTo(listSizeBefore + 1);
253+
}
254+
255+
@Test
256+
@SneakyThrows
257+
void saveAllMyRequestLoan_ShouldReturnOk_ButOperationFailed_Test() {
258+
String jwt = JwtTestUtils.generateJWT("user3@test.com", rsaJsonWebKey, wireMockServer, realmAccessClaimsUser);
259+
/* Получим количество записей в БД */
260+
List<LoanReadDto> loansList = loanService.findAll();
261+
Integer listSizeBefore = loansList.size();
262+
263+
/* Подготовим данные для сохранения в БД */
264+
String strList = objectMapper.writeValueAsString(testList);
265+
266+
/* Делаем запрос на сохранение */
267+
mockMvc.perform(post("/api/save-all-loans")
268+
.contentType(MediaType.APPLICATION_JSON)
269+
.content(strList)
270+
.header("Authorization", "Bearer " + jwt))
271+
.andExpect(status().isOk())
272+
.andExpect(content().string("Operation is failed!"));
273+
274+
/* Проверяем количество записей в БД после сохранения списка кредитов - неизменен */
275+
Integer listSizeAfter = loanService.findAll().size();
276+
assertThat(listSizeAfter).isEqualTo(listSizeBefore);
277+
}
278+
279+
@Test
280+
@SneakyThrows
281+
void getAllLoanByType_ShouldReturnOkForRoleAdmin_AndListOfLoansByType_Test() {
282+
String jwt = JwtTestUtils.generateJWT(EXIST_EMAIL, rsaJsonWebKey, wireMockServer, realmAccessClaimsAdmin);
283+
String loanType = "Home";
284+
285+
MvcResult result = mockMvc.perform(get("/api/get-all-loans-by-type/" + loanType)
286+
.header("Authorization", "Bearer " + jwt))
287+
.andExpect(status().isOk())
288+
.andReturn();
289+
290+
String strRes = result.getResponse().getContentAsString();
291+
292+
List<LoanReadDto> respList = objectMapper.readValue(strRes, new TypeReference<List<LoanReadDto>>() {});
293+
294+
assertThat(respList.size()).isGreaterThan(1);
295+
}
296+
297+
@Test
298+
@SneakyThrows
299+
void getAllLoanByType_ShouldReturnForbidden_NotAdminAuth_Test() {
300+
String jwt = JwtTestUtils.generateJWT("user3@test.com", rsaJsonWebKey, wireMockServer, realmAccessClaimsUser);
301+
String loanType = "Home";
302+
303+
mockMvc.perform(get("/api/get-all-loans-by-type/" + loanType)
304+
.header("Authorization", "Bearer " + jwt))
305+
.andExpect(status().isBadRequest())
306+
.andExpect(content().string("{\"exceptionMsg\":\"Access Denied\"}"));
307+
}
308+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /