Skip to content

Commit 001043d

Browse files
committed
test: some more tests
1 parent 8532c6e commit 001043d

File tree

13 files changed

+189
-60
lines changed

13 files changed

+189
-60
lines changed

api/.vscode/launch.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66
"configurations": [
77
{
88
"type": "java",
9-
"name": "Debug (Attach)",
9+
"name": "Debug (local)",
10+
"request": "launch",
11+
"mainClass": "com.github.throyer.common.springboot.Application"
12+
},
13+
{
14+
"type": "java",
15+
"name": "Debug (Attach Docker)",
1016
"projectName": "Vendas",
1117
"request": "attach",
1218
"hostName": "127.0.0.1",

api/.vscode/settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
{
22
"cSpell.words": [
3+
"hamcrest",
34
"instanceof",
45
"jooq",
6+
"servlet",
57
"Servlet",
68
"springboot",
79
"springframework",
810
"throyer"
9-
]
11+
],
12+
"java.configuration.updateBuildConfiguration": "automatic"
1013
}

api/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@
206206
<artifactId>spring-boot-maven-plugin</artifactId>
207207
<configuration>
208208
<jvmArguments>
209-
-agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,server=y,suspend=n
209+
-agentlib:jdwp=transport=dt_socket,address=*:8000,server=y,suspend=n
210210
</jvmArguments>
211211
</configuration>
212212
<executions>

api/src/main/java/com/github/throyer/common/springboot/constants/MAIL.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.github.throyer.common.springboot.constants;
22

33
public class MAIL {
4+
private MAIL () {}
5+
46
public static final Boolean CONTENT_IS_HTML = true;
57
public static final String ERROR_SENDING_EMAIL_MESSAGE = "Error sending email.";
8+
public static final String ERROR_SENDING_EMAIL_MESSAGE_TO = "Error sending email to: {}";
69
public static final String EMAIL_SUCCESSFULLY_SENT_TO = "Email successfully sent to: {}";
710
public static final String EMAIL_SENT_SUCCESSFULLY_MESSAGE_LOG_TEMPLATE = "email sent successfully to: %s";
811
public static final String UNABLE_TO_SEND_EMAIL_MESSAGE_TEMPLATE = "Unable to send email to: %s";

api/src/main/java/com/github/throyer/common/springboot/controllers/api/ApiController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public Hello index() {
2424
"I'm going to make him an offer he can't refuse. - The Godfather",
2525
"May the Force be with you. - Star Wars",
2626
"You're gonna need a bigger boat. - Jaws",
27-
"Dadinho é o caralho! meu nome é Zé Pequeno, porra!",
27+
"Dadinho é o caralho! meu nome é Zé Pequeno, porra! - Cidade de Deus",
2828
"Say “hello” to my little friend! - Scarface",
2929
"Bond. James Bond. - Dr. No",
3030
"Hasta la vista, baby. - Terminator 2",

api/src/main/java/com/github/throyer/common/springboot/domain/recovery/service/RecoveryService.java

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
package com.github.throyer.common.springboot.domain.recovery.service;
22

3+
import static com.github.throyer.common.springboot.constants.MAIL.ERROR_SENDING_EMAIL_MESSAGE_TO;
4+
import static com.github.throyer.common.springboot.constants.PASSWORD_RECOVERY.MINUTES_TO_EXPIRE_RECOVERY_CODE;
5+
import static com.github.throyer.common.springboot.constants.PASSWORD_RECOVERY.SUBJECT_PASSWORD_RECOVERY_CODE;
6+
7+
import java.util.logging.Level;
8+
import java.util.logging.Logger;
9+
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.stereotype.Service;
12+
313
import com.github.throyer.common.springboot.domain.mail.service.MailService;
414
import com.github.throyer.common.springboot.domain.recovery.entity.Recovery;
515
import com.github.throyer.common.springboot.domain.recovery.model.RecoveryEmail;
616
import com.github.throyer.common.springboot.domain.recovery.repository.RecoveryRepository;
717
import com.github.throyer.common.springboot.domain.user.repository.UserRepository;
8-
import org.springframework.beans.factory.annotation.Autowired;
9-
import org.springframework.stereotype.Service;
10-
11-
import java.util.logging.Logger;
12-
13-
import static com.github.throyer.common.springboot.constants.MAIL.EMAIL_SENT_SUCCESSFULLY_MESSAGE_LOG_TEMPLATE;
14-
import static com.github.throyer.common.springboot.constants.MAIL.UNABLE_TO_SEND_EMAIL_MESSAGE_TEMPLATE;
15-
import static com.github.throyer.common.springboot.constants.PASSWORD_RECOVERY.MINUTES_TO_EXPIRE_RECOVERY_CODE;
16-
import static com.github.throyer.common.springboot.constants.PASSWORD_RECOVERY.SUBJECT_PASSWORD_RECOVERY_CODE;
17-
import static java.lang.String.format;
18-
import static java.util.logging.Level.INFO;
19-
import static java.util.logging.Level.WARNING;
2018

2119
@Service
2220
public class RecoveryService {
@@ -50,23 +48,21 @@ public void recovery(String email) {
5048

5149
recoveries.save(recovery);
5250

53-
var sendEmailBackground = new Thread(() -> {
54-
try {
55-
var recoveryEmail = new RecoveryEmail(
56-
email,
57-
SUBJECT_PASSWORD_RECOVERY_CODE,
58-
user.get().getName(),
59-
recovery.getCode()
60-
);
51+
var sendEmailInBackground = new Thread(() -> {
52+
var recoveryEmail = new RecoveryEmail(
53+
email,
54+
SUBJECT_PASSWORD_RECOVERY_CODE,
55+
user.get().getName(),
56+
recovery.getCode()
57+
);
6158

59+
try {
6260
service.send(recoveryEmail);
63-
64-
LOGGER.log(INFO, format(EMAIL_SENT_SUCCESSFULLY_MESSAGE_LOG_TEMPLATE, email));
6561
} catch (Exception exception) {
66-
LOGGER.log(WARNING, format(UNABLE_TO_SEND_EMAIL_MESSAGE_TEMPLATE, email), exception);
62+
LOGGER.log(Level.INFO, ERROR_SENDING_EMAIL_MESSAGE_TO, email);
6763
}
6864
});
6965

70-
sendEmailBackground.start();
66+
sendEmailInBackground.start();
7167
}
7268
}

api/src/test/java/com/github/throyer/common/springboot/InternationalizationTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
2020
@AutoConfigureDataJpa
2121
@AutoConfigureMockMvc
22-
public class InternationalizationTests {
22+
class InternationalizationTests {
2323

2424
@Autowired
2525
private MockMvc api;
2626

2727
@Test
2828
@DisplayName("Deve retornar as mensagens de erro em pt BR.")
29-
public void should_return_error_messages_in_pt_BR() throws Exception {
29+
void should_return_error_messages_in_pt_BR() throws Exception {
3030
var body = "{ \"password\": \"senha_bem_segura_1234\", \"email\": \"email@email.com\" }";
3131

3232
api.perform(post("/api/sessions")
@@ -39,7 +39,7 @@ public void should_return_error_messages_in_pt_BR() throws Exception {
3939

4040
@Test
4141
@DisplayName("Deve retornar as mensagens de erro em Inglês.")
42-
public void should_return_error_messages_in_english() throws Exception {
42+
void should_return_error_messages_in_english() throws Exception {
4343
var body = "{ \"password\": \"senha_bem_segura_1234\", \"email\": \"email@email.com\" }";
4444

4545
api.perform(post("/api/sessions")

api/src/test/java/com/github/throyer/common/springboot/RateLimitTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
@TestInstance(PER_CLASS)
2525
@SpringBootTest(webEnvironment = MOCK)
2626
@DirtiesContext(classMode = BEFORE_CLASS)
27-
public class RateLimitTests {
27+
class RateLimitTests {
2828
@Autowired
2929
private MockMvc api;
3030

3131
@Test
3232
@DisplayName("Deve retornar TOO_MANY_REQUESTS quando a quantidade de requests passar do limite.")
33-
public void should_return_TOO_MANY_REQUESTS_when_number_of_requests_exceeds_the_limit() throws Exception {
33+
void should_return_TOO_MANY_REQUESTS_when_number_of_requests_exceeds_the_limit() throws Exception {
3434
var request = get("/api")
3535
.header(CONTENT_TYPE, APPLICATION_JSON);
3636

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.github.throyer.common.springboot.controllers;
2+
3+
import com.github.throyer.common.springboot.utils.JSON;
4+
import static com.github.throyer.common.springboot.utils.Random.user;
5+
import static org.junit.jupiter.api.Assertions.assertFalse;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
7+
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
8+
import static org.springframework.http.MediaType.APPLICATION_JSON;
9+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
10+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
11+
12+
import java.util.Map;
13+
14+
import org.junit.jupiter.api.DisplayName;
15+
import org.junit.jupiter.api.Test;
16+
import org.springframework.beans.factory.annotation.Autowired;
17+
import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa;
18+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
19+
import org.springframework.boot.test.context.SpringBootTest;
20+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
21+
import org.springframework.test.annotation.DirtiesContext;
22+
import org.springframework.test.annotation.DirtiesContext.ClassMode;
23+
import org.springframework.test.web.servlet.MockMvc;
24+
25+
import com.github.throyer.common.springboot.domain.recovery.repository.RecoveryRepository;
26+
import com.github.throyer.common.springboot.domain.user.repository.UserRepository;
27+
28+
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
29+
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
30+
@AutoConfigureDataJpa
31+
@AutoConfigureMockMvc
32+
class RecoveriesControllerTests {
33+
34+
@Autowired
35+
private RecoveryRepository recoveryRepository;
36+
37+
@Autowired
38+
private UserRepository userRepository;
39+
40+
@Autowired
41+
private MockMvc api;
42+
43+
@Test
44+
@DisplayName("Deve responder No Content quando email for invalido.")
45+
void should_return_no_content_on_invalid_email() throws Exception {
46+
47+
var json = JSON.stringify(Map.of(
48+
"email", "jubileu.da.silva@email.fake.com"
49+
));
50+
51+
api.perform(
52+
post("/api/recoveries")
53+
.header(CONTENT_TYPE, APPLICATION_JSON)
54+
.content(json))
55+
.andExpect(status().isNoContent());
56+
}
57+
58+
@Test
59+
@DisplayName("Deve responder No Content quando email for valido.")
60+
void should_return_no_content_on_valid_email() throws Exception {
61+
62+
var user = user();
63+
64+
userRepository.save(user);
65+
66+
var json = JSON.stringify(Map.of(
67+
"email", user.getEmail()
68+
));
69+
70+
api.perform(
71+
post("/api/recoveries")
72+
.header(CONTENT_TYPE, APPLICATION_JSON)
73+
.content(json))
74+
.andExpect(status().isNoContent());
75+
}
76+
77+
@Test
78+
@DisplayName("Deve confirmar o código quando ele for valido for valido.")
79+
void should_confirm_code_when_is_valid() throws Exception {
80+
81+
var user = userRepository.save(user());
82+
83+
var recoveryBody = JSON.stringify(Map.of(
84+
"email", user.getEmail()
85+
));
86+
87+
api.perform(
88+
post("/api/recoveries")
89+
.header(CONTENT_TYPE, APPLICATION_JSON)
90+
.content(recoveryBody))
91+
.andExpect(status().isNoContent());
92+
93+
var unconfirmedRecovery = recoveryRepository
94+
.findFirstOptionalByUser_IdAndConfirmedIsFalseAndUsedIsFalseOrderByExpiresInDesc(user.getId())
95+
.orElseThrow(() -> new RuntimeException("recovery code not found"));
96+
97+
assertFalse(unconfirmedRecovery.isConfirmed());
98+
assertFalse(unconfirmedRecovery.isUsed());
99+
100+
var confirmBody = JSON.stringify(Map.of(
101+
"email", user.getEmail(),
102+
"code", unconfirmedRecovery.getCode()
103+
));
104+
105+
api.perform(
106+
post("/api/recoveries/confirm")
107+
.header(CONTENT_TYPE, APPLICATION_JSON)
108+
.content(confirmBody))
109+
.andExpect(status().isNoContent());
110+
111+
var confirmedRecovery = recoveryRepository
112+
.findFirstOptionalByUser_IdAndConfirmedIsTrueAndUsedIsFalseOrderByExpiresInDesc(user.getId())
113+
.orElseThrow(() -> new RuntimeException("recovery code not found"));
114+
115+
assertTrue(confirmedRecovery.isConfirmed());
116+
assertFalse(unconfirmedRecovery.isUsed());
117+
}
118+
}

api/src/test/java/com/github/throyer/common/springboot/controllers/SessionsControllerTests.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
3131
@AutoConfigureDataJpa
3232
@AutoConfigureMockMvc
33-
public class SessionsControllerTests {
33+
class SessionsControllerTests {
3434

3535
@Autowired
3636
private MockMvc api;
@@ -40,7 +40,7 @@ public class SessionsControllerTests {
4040

4141
@Test
4242
@DisplayName("deve retornar OK quando a senha estiver correta")
43-
public void should_return_OK_when_password_is_correct() throws Exception {
43+
void should_return_OK_when_password_is_correct() throws Exception {
4444

4545
var user = user();
4646

@@ -59,7 +59,7 @@ public void should_return_OK_when_password_is_correct() throws Exception {
5959

6060
@Test
6161
@DisplayName("deve retornar FORBIDDEN quando a senha estiver incorreta")
62-
public void should_return_FORBIDDEN_when_password_is_incorrect() throws Exception {
62+
void should_return_FORBIDDEN_when_password_is_incorrect() throws Exception {
6363
var user = repository.save(user());
6464

6565
var body = JSON.stringify(Map.of(
@@ -75,7 +75,7 @@ public void should_return_FORBIDDEN_when_password_is_incorrect() throws Exceptio
7575

7676
@Test
7777
@DisplayName("deve retornar FORBIDDEN quando o usuário não existir")
78-
public void should_return_FORBIDDEN_when_user_does_not_exist() throws Exception {
78+
void should_return_FORBIDDEN_when_user_does_not_exist() throws Exception {
7979
var body = JSON.stringify(Map.of(
8080
"email", "this.not.exist@email.com",
8181
"password", "Írineu! você não sabe, nem eu!"
@@ -89,15 +89,15 @@ public void should_return_FORBIDDEN_when_user_does_not_exist() throws Exception
8989

9090
@Test
9191
@DisplayName("não deve aceitar requisições sem o token no cabeçalho quando as rotas forem privadas")
92-
public void should_not_accept_requests_without_token_in_header_when_routes_are_private() throws Exception {
92+
void should_not_accept_requests_without_token_in_header_when_routes_are_private() throws Exception {
9393
api.perform(get("/api/users"))
9494
.andExpect(status().isForbidden())
9595
.andExpect(jsonPath("$.message").value("Can't find token on Authorization header."));
9696
}
9797

9898
@Test
9999
@DisplayName("não deve aceitar requisições com o token expirado")
100-
public void should_not_accept_requests_with_token_expired() throws Exception {
100+
void should_not_accept_requests_with_token_expired() throws Exception {
101101
var expiredToken = token(now().minusHours(24), "ADM");
102102

103103
api.perform(get("/api/users")
@@ -108,7 +108,7 @@ public void should_not_accept_requests_with_token_expired() throws Exception {
108108

109109
@Test
110110
@DisplayName("deve aceitar requisições com o token um válido")
111-
public void should_accept_requests_with_token_valid() throws Exception {
111+
void should_accept_requests_with_token_valid() throws Exception {
112112
var token = token("ADM");
113113

114114
api.perform(get("/api/users")
@@ -119,7 +119,7 @@ public void should_accept_requests_with_token_valid() throws Exception {
119119

120120
@Test
121121
@DisplayName("não deve aceitar requisições com o token um inválido")
122-
public void must_not_accept_requests_with_an_invalid_token() throws Exception {
122+
void must_not_accept_requests_with_an_invalid_token() throws Exception {
123123
var token = token(now().plusHours(24),"ADM", "this_is_not_my_secret");
124124

125125
api.perform(get("/api/users")
@@ -130,7 +130,7 @@ public void must_not_accept_requests_with_an_invalid_token() throws Exception {
130130

131131
@Test
132132
@DisplayName("não deve aceitar requisições com o token sem a role correta")
133-
public void must_not_accept_requests_with_token_without_the_correct_role() throws Exception {
133+
void must_not_accept_requests_with_token_without_the_correct_role() throws Exception {
134134
var token = token("THIS_IS_NOT_CORRECT_ROLE");
135135

136136
api.perform(get("/api/users")
@@ -141,14 +141,14 @@ public void must_not_accept_requests_with_token_without_the_correct_role() throw
141141

142142
@Test
143143
@DisplayName("deve aceitar requisições sem token em rotas publicas")
144-
public void must_accept_requests_without_token_on_public_routes() throws Exception {
144+
void must_accept_requests_without_token_on_public_routes() throws Exception {
145145
api.perform(get("/api"))
146146
.andExpect(status().isOk());
147147
}
148148

149149
@Test
150150
@DisplayName("deve aceitar requisições sem token em rotas publicas porem com um token invalido no header")
151-
public void must_accept_requests_without_token_on_public_routes_but_with_invalid_token_on_header() throws Exception {
151+
void must_accept_requests_without_token_on_public_routes_but_with_invalid_token_on_header() throws Exception {
152152
api.perform(get("/api").header(AUTHORIZATION, token("ADM", "this_is_not_my_secret")))
153153
.andExpect(status().isOk());
154154
}

0 commit comments

Comments
 (0)