Started work on tests

This commit is contained in:
Claudio Maggioni 2020-03-05 12:42:53 +01:00
parent 6d2f7a25fb
commit e8a55ae131
7 changed files with 277 additions and 15 deletions

View file

@ -23,16 +23,23 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt:0.9.1' implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'org.springframework.security:spring-security-web' implementation 'org.springframework.security:spring-security-web'
implementation 'org.postgresql:postgresql' implementation 'org.postgresql:postgresql'
compile "io.springfox:springfox-swagger2:2.9.2" implementation 'com.google.code.gson:gson'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2' compile 'io.springfox:springfox-swagger2:2.9.2'
compile 'io.springfox:springfox-swagger-ui:2.9.2'
implementation('org.springframework.boot:spring-boot-starter-web') { implementation('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-json' exclude group: 'org.springframework.boot', module: 'spring-boot-starter-json'
} }
implementation 'com.google.code.gson:gson'
testImplementation('org.springframework.boot:spring-boot-starter-test') { testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
} }
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'com.h2database:h2:1.3.148'
// Fixes https://stackoverflow.com/a/60455550
testImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.11'
} }
test { test {

View file

@ -4,6 +4,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtil;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTResponse; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTResponse;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.UserUpdateRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.UserUpdateRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.UnauthorizedException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.UserNotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.UserNotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import io.swagger.annotations.Authorization; import io.swagger.annotations.Authorization;
@ -44,7 +45,7 @@ public class AuthenticationController {
@PostMapping("/login") @PostMapping("/login")
public JWTResponse login(@Valid @RequestBody JWTRequest authenticationRequest) public JWTResponse login(@Valid @RequestBody JWTRequest authenticationRequest)
throws Exception { throws UnauthorizedException, UserNotFoundException {
final UserDetails userDetails; final UserDetails userDetails;
if (authenticationRequest.getUsernameOrEmail().contains("@")) { if (authenticationRequest.getUsernameOrEmail().contains("@")) {
// usernameOrEmail contains an email, so fetch the corresponding username // usernameOrEmail contains an email, so fetch the corresponding username
@ -86,16 +87,14 @@ public class AuthenticationController {
return userRepository.save(oldUser); return userRepository.save(oldUser);
} }
private void authenticate(String username, String password) throws Exception { private void authenticate(String username, String password) throws UnauthorizedException {
try { try {
authenticationManager.authenticate( authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(username, password)); new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) { } catch (DisabledException e) {
e.printStackTrace(); throw new UnauthorizedException(true);
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) { } catch (BadCredentialsException e) {
e.printStackTrace(); throw new UnauthorizedException(false);
throw new Exception("INVALID_CREDENTIALS", e);
} }
} }
} }

View file

@ -0,0 +1,18 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.error;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends Exception {
private final boolean isUserDisabled;
public UnauthorizedException(boolean isDisabled) {
super("Access denied: " + (isDisabled ? "user is disabled" : "wrong credentials"));
this.isUserDisabled = isDisabled;
}
public boolean isUserDisabled() {
return isUserDisabled;
}
}

View file

@ -0,0 +1,171 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut;
import static org.assertj.core.api.Assertions.assertThat;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTResponse;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.OkResponse;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.UserRegistrationRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.UnauthorizedException;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@AutoConfigureMockMvc
public class AuthenticationTests extends SmartHutTest {
@Autowired private TestRestTemplate restTemplate;
@Override
protected void setUp() {
final UserRegistrationRequest request = new UserRegistrationRequest();
request.setName("Disabled User");
request.setEmail("disabled@example.com");
request.setUsername("disabled");
request.setPassword("password");
final ResponseEntity<OkResponse> res =
this.restTemplate.postForEntity(this.url("/register"), request, OkResponse.class);
assertThat(res.getStatusCode().equals(HttpStatus.OK));
final UserRegistrationRequest request2 = new UserRegistrationRequest();
request2.setName("Enabled User");
request2.setEmail("enabled@example.com");
request2.setUsername("enabled");
request2.setPassword("password");
final ResponseEntity<OkResponse> res2 =
this.restTemplate.postForEntity(this.url("/register"), request, OkResponse.class);
assertThat(res2.getStatusCode().equals(HttpStatus.OK));
// TODO: email confirmation for res2
}
@Test
public void registrationShouldReturnBadRequestWithIncorrectFields() {
final Map<String, Object> badJSON = Map.of("luciano", "goretti", "danilo", "malusa");
assertThat(
this.restTemplate
.postForEntity(url("/register"), badJSON, JWTResponse.class)
.getStatusCode()
.equals(HttpStatus.BAD_REQUEST));
}
@Test
public void registrationShouldReturnBadRequestWithShortPassword() {
final UserRegistrationRequest request = new UserRegistrationRequest();
request.setName("Mario Goretti");
request.setEmail("test@example.com");
request.setUsername("mgo");
request.setPassword("passw");
final ResponseEntity<JsonObject> res =
this.restTemplate.postForEntity(url("/register"), request, JsonObject.class);
assertThat(res.getStatusCode().equals(HttpStatus.BAD_REQUEST));
assertThat(res.getBody() != null);
final JsonArray errors = res.getBody().getAsJsonArray("errors");
assertThat(errors.size() == 1);
assertThat(errors.get(0).getAsJsonObject().get("field").getAsString().equals("password"));
}
@Test
public void registrationShouldReturnBadRequestWithWrongEmail() {
final UserRegistrationRequest request = new UserRegistrationRequest();
request.setName("Mario Goretti");
request.setEmail("test@example");
request.setUsername("mgo");
request.setPassword("password");
final ResponseEntity<JsonObject> res =
this.restTemplate.postForEntity(url("/register"), request, JsonObject.class);
assertThat(res.getStatusCode().equals(HttpStatus.BAD_REQUEST));
assertThat(res.getBody() != null);
final JsonArray errors = res.getBody().getAsJsonArray("errors");
assertThat(errors.size() == 1);
assertThat(errors.get(0).getAsJsonObject().get("field").getAsString().equals("email"));
}
@Test
public void registrationShouldReturnBadRequestWithNoName() {
final UserRegistrationRequest request = new UserRegistrationRequest();
request.setEmail("test@example.com");
request.setUsername("mgo");
request.setPassword("password");
final ResponseEntity<JsonObject> res =
this.restTemplate.postForEntity(url("/register"), request, JsonObject.class);
assertThat(res.getStatusCode().equals(HttpStatus.BAD_REQUEST));
assertThat(res.getBody() != null);
final JsonArray errors = res.getBody().getAsJsonArray("errors");
assertThat(errors.size() == 1);
assertThat(errors.get(0).getAsJsonObject().get("field").getAsString().equals("name"));
}
@Test
public void registrationShouldReturnBadRequestWithNoUsername() {
final UserRegistrationRequest request = new UserRegistrationRequest();
request.setName("Mario Goretti");
request.setEmail("test@example.com");
request.setPassword("password");
final ResponseEntity<JsonObject> res =
this.restTemplate.postForEntity(url("/register"), request, JsonObject.class);
assertThat(res.getStatusCode().equals(HttpStatus.BAD_REQUEST));
assertThat(res.getBody() != null);
final JsonArray errors = res.getBody().getAsJsonArray("errors");
assertThat(errors.size() == 1);
assertThat(errors.get(0).getAsJsonObject().get("field").getAsString().equals("username"));
}
@Test
public void loginShouldReturnBadRequestWithIncorrectFields() {
final Map<String, Object> badJSON = Map.of("badkey", 3, "password", "ciaomamma");
assertThat(
this.restTemplate
.postForEntity(url("/auth/login"), badJSON, JWTResponse.class)
.getStatusCode()
.equals(HttpStatus.BAD_REQUEST));
}
@Test
public void loginShouldReturnUnauthorizedWithNonExistantUser() {
final JWTRequest request = new JWTRequest();
request.setUsernameOrEmail("roberto");
request.setPassword("ciaomamma");
final ResponseEntity<UnauthorizedException> res =
this.restTemplate.postForEntity(
url("/auth/login"), request, UnauthorizedException.class);
assertThat(res.getStatusCode().equals(HttpStatus.UNAUTHORIZED));
assertThat(res.getBody() != null);
assertThat(!res.getBody().isUserDisabled());
}
@Test
public void loginShouldReturnUnauthorizedWithDisabledUser() {
final JWTRequest request = new JWTRequest();
request.setUsernameOrEmail("disabled");
request.setPassword("password");
final ResponseEntity<UnauthorizedException> res =
this.restTemplate.postForEntity(
url("/auth/login"), request, UnauthorizedException.class);
assertThat(res.getStatusCode().equals(HttpStatus.UNAUTHORIZED));
assertThat(res.getBody() != null);
assertThat(res.getBody().isUserDisabled());
}
}

View file

@ -0,0 +1,25 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut;
import org.junit.jupiter.api.BeforeEach;
public abstract class SmartHutTest {
private boolean setupDone = false;
protected final String getBaseURL() {
return "http://localhost:2000/";
}
protected final String url(final String url) {
return getBaseURL() + url;
}
protected void setUp() {}
@BeforeEach
void setUpHack() {
if (!setupDone) {
setUp();
setupDone = true;
}
}
}

View file

@ -1,11 +1,26 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut; package ch.usi.inf.sa4.sanmarinoes.smarthut;
import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest import org.junit.jupiter.api.Test;
class SmarthutApplicationTests { import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@AutoConfigureMockMvc
public class SmarthutApplicationTests extends SmartHutTest {
@Autowired private TestRestTemplate restTemplate;
@Test @Test
void contextLoads() {} public void anonymousGreetingShouldNotBeAuthorized() throws Exception {
assertThat(
this.restTemplate
.getForEntity(getBaseURL(), Void.class)
.getStatusCode()
.equals(HttpStatus.UNAUTHORIZED));
}
} }

View file

@ -0,0 +1,27 @@
spring.http.converters.preferred-json-mapper=gson
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
# Hibernate properties
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
spring.jpa.properties.hibernate.format_sql=true
jwt.secret=thiskeymustbeverylongorthethingcomplainssoiamjustgoingtowritehereabunchofgarbageciaomamma
spring.mail.test-connection=true
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.username=smarthut.sm@gmail.com
spring.mail.password=dcadvbagqfkwbfts
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
server.port = 2000