Commit e2374529 authored by Alejandro's avatar Alejandro

Adds Pets Test

Adds pets test and all changes for use them(DB,XML)...
parent c079f4af
package es.uvigo.esei.daa.dao;
import javax.sql.DataSource;
import es.uvigo.esei.daa.entities.Pet;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static es.uvigo.esei.daa.dataset.PeopleDataset.nonExistentId;
import static es.uvigo.esei.daa.dataset.PetsDataset.*;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.equalsToPet;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import es.uvigo.esei.daa.listeners.ApplicationContextBinding;
import es.uvigo.esei.daa.listeners.ApplicationContextJndiBindingTestExecutionListener;
import es.uvigo.esei.daa.listeners.DbManagement;
import es.uvigo.esei.daa.listeners.DbManagementTestExecutionListener;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:contexts/mem-context.xml")
@TestExecutionListeners({
DbUnitTestExecutionListener.class,
DbManagementTestExecutionListener.class,
ApplicationContextJndiBindingTestExecutionListener.class
})
@ApplicationContextBinding(
jndiUrl = "java:/comp/env/jdbc/daaexample",
type = DataSource.class
)
@DbManagement(
create = "classpath:db/hsqldb.sql",
drop = "classpath:db/hsqldb-drop.sql"
)
@DatabaseSetup("/datasets/dataset-pet.xml")
@ExpectedDatabase("/datasets/dataset-pet.xml")
public class PetsDAOTest {
private PetDAO dao;
@Before
public void setUp() throws Exception {
this.dao = new PetDAO();
}
@Test
public void testList() throws DAOException {
assertThat(this.dao.list(), containsPetsInAnyOrder(pets()));
}
@Test
public void testGet() throws DAOException {
final Pet pet = this.dao.get(existentId());
assertThat(pet, is(equalsToPet(existentPet())));
}
@Test(expected = IllegalArgumentException.class)
public void testGetNonExistentId() throws DAOException {
this.dao.get(nonExistentId());
}
@Test
@ExpectedDatabase("/datasets/dataset-pet-delete.xml")
public void testDelete() throws DAOException {
this.dao.delete(existentId());
}
@Test(expected = IllegalArgumentException.class)
public void testDeleteNonExistentId() throws DAOException {
this.dao.delete(nonExistentId());
}
@Test
@ExpectedDatabase("/datasets/dataset-pet-modify.xml")
public void testModify() throws DAOException {
final Pet pet = existentPet();
pet.setName(newName());
pet.setType(newType());
pet.setPerson(newPerson());
this.dao.modify(pet);
final Pet persistentPerson = this.dao.get(pet.getId());
assertThat(persistentPerson, is(equalsToPet(pet)));
}
@Test(expected = IllegalArgumentException.class)
public void testModifyNonExistentId() throws DAOException {
this.dao.modify(nonExistentPet());
}
@Test(expected = IllegalArgumentException.class)
public void testModifyNullPet() throws DAOException {
this.dao.modify(null);
}
@Test
@ExpectedDatabase("/datasets/dataset-pet-add.xml")
public void testAdd() throws DAOException {
final Pet pet = this.dao.add(newName(), newType(),newPerson());
assertThat(pet, is(equalsToPet(newPet())));
final Pet persistentPet = this.dao.get(pet.getId());
assertThat(persistentPet, is(equalsToPet(newPet())));
}
@Test(expected = IllegalArgumentException.class)
public void testAddNullName() throws DAOException {
this.dao.add(null, newType(),newPerson());
}
@Test(expected = IllegalArgumentException.class)
public void testAddNullType() throws DAOException {
this.dao.add(newName(), null,newPerson());
}
}
package es.uvigo.esei.daa.dao;
import java.sql.SQLException;
import org.junit.Test;
import com.mysql.jdbc.Statement;
import es.uvigo.esei.daa.entities.Pet;
import es.uvigo.esei.daa.util.DatabaseQueryUnitTest;
import static es.uvigo.esei.daa.dataset.PetsDataset.*;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.equalsToPet;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.anyString;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.reset;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class PetsDAOUnitTest extends DatabaseQueryUnitTest {
@Test
public void testList() throws Exception {
final Pet[] pets = pets();
for (Pet pet : pets) {
expectPetRow(pet);
}
expect(result.next()).andReturn(false);
result.close();
replayAll();
final PetDAO petsDAO = new PetDAO();
assertThat(petsDAO.list(), containsPetsInAnyOrder(pets));
}
@Test(expected = DAOException.class)
public void testListUnexpectedException() throws Exception {
expect(result.next()).andThrow(new SQLException());
result.close();
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.list();
}
@Test
public void testGet() throws Exception {
final Pet existentPet = existentPet();
expectPetRow(existentPet);
result.close();
replayAll();
final PetDAO petDAO = new PetDAO();
Pet prueba = petDAO.get(existentId());
System.out.println(prueba.getId());
System.out.println(existentPet.getId());
System.out.println(prueba.getName());
System.out.println(existentPet.getName());
System.out.println(existentPet.getType());
System.out.println(prueba.getType());
System.out.println(prueba.getPerson());
System.out.println(existentPet.getPerson());
System.out.println(prueba.equals(existentPet));
assertThat(prueba, is(equalTo(existentPet)));
}
@Test(expected = IllegalArgumentException.class)
public void testGetMissing() throws Exception {
expect(result.next()).andReturn(false);
result.close();
replayAll();
final PetDAO petsDao = new PetDAO();
petsDao.get(existentId());
}
@Test(expected = DAOException.class)
public void testGetUnexpectedException() throws Exception {
expect(result.next()).andThrow(new SQLException());
result.close();
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.get(existentId());
}
@Test
public void testAdd() throws Exception {
final Pet pet = newPet();
reset(connection);
expect(connection.prepareStatement(anyString(), eq(Statement.RETURN_GENERATED_KEYS)))
.andReturn(statement);
expect(statement.executeUpdate()).andReturn(1);
expect(statement.getGeneratedKeys()).andReturn(result);
// Key retrieval
expect(result.next()).andReturn(true);
expect(result.getInt(1)).andReturn(pet.getId());
connection.close();
result.close();
replayAll();
final PetDAO petsDAO = new PetDAO();
final Pet newPet = petsDAO.add(pet.getName(), pet.getType(),pet.getPerson());
assertThat(newPet, is(equalsToPet(pet)));
}
@Test(expected = IllegalArgumentException.class)
public void testAddNullName() throws Exception {
replayAll();
final PetDAO petsDAO = new PetDAO();
resetAll(); // No expectations
petsDAO.add(null, newType(),newPerson());
}
@Test(expected = IllegalArgumentException.class)
public void testAddNullType() throws Exception {
replayAll();
final PetDAO petsDAO = new PetDAO();
resetAll(); // No expectations
petsDAO.add(newName(), null,newPerson());
}
@Test(expected = DAOException.class)
public void testAddZeroUpdatedRows() throws Exception {
reset(connection);
expect(connection.prepareStatement(anyString(), eq(1)))
.andReturn(statement);
expect(statement.executeUpdate()).andReturn(0);
connection.close();
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.add(newName(), newType(), newPerson());
}
@Test(expected = DAOException.class)
public void testAddNoGeneratedKey() throws Exception {
reset(connection);
expect(connection.prepareStatement(anyString(), eq(1)))
.andReturn(statement);
expect(statement.executeUpdate()).andReturn(1);
expect(statement.getGeneratedKeys()).andReturn(result);
expect(result.next()).andReturn(false);
result.close();
connection.close();
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.add(newName(), newType(),newPerson());
}
@Test(expected = DAOException.class)
public void testAddUnexpectedException() throws Exception {
reset(connection);
expect(connection.prepareStatement(anyString(), eq(1)))
.andReturn(statement);
expect(statement.executeUpdate()).andThrow(new SQLException());
connection.close();
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.add(newName(), newType(),newPerson());
}
@Test
public void testDelete() throws Exception {
expect(statement.executeUpdate()).andReturn(1);
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.delete(existentId());
}
@Test(expected = IllegalArgumentException.class)
public void testDeleteInvalidId() throws Exception {
expect(statement.executeUpdate()).andReturn(0);
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.delete(existentId());
}
@Test(expected = DAOException.class)
public void testDeleteUnexpectedException() throws Exception {
expect(statement.executeUpdate()).andThrow(new SQLException());
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.delete(existentId());
}
@Test
public void testModify() throws Exception {
expect(statement.executeUpdate()).andReturn(1);
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.modify(existentPet());
}
@Test(expected = IllegalArgumentException.class)
public void testModifyNullPet() throws Exception {
replayAll();
final PetDAO petsDAO = new PetDAO();
resetAll(); // No expectations
petsDAO.modify(null);
}
@Test(expected = IllegalArgumentException.class)
public void testModifyZeroUpdatedRows() throws Exception {
expect(statement.executeUpdate()).andReturn(0);
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.modify(existentPet());
}
@Test(expected = DAOException.class)
public void testModifyUnexpectedException() throws Exception {
expect(statement.executeUpdate()).andThrow(new SQLException());
replayAll();
final PetDAO petsDAO = new PetDAO();
petsDAO.modify(existentPet());
}
private void expectPetRow(Pet pet) throws SQLException {
expect(result.next()).andReturn(true);
expect(result.getInt("id")).andReturn(pet.getId());
expect(result.getString("name")).andReturn(pet.getName());
expect(result.getString("type")).andReturn(pet.getType());
expect(result.getInt("person")).andReturn(pet.getPerson());
}
}
package es.uvigo.esei.daa.dataset;
import es.uvigo.esei.daa.entities.Pet;
import java.util.Arrays;
import java.util.function.Predicate;
import static java.util.Arrays.binarySearch;
import static java.util.Arrays.stream;
public class PetsDataset {
private PetsDataset(){}
public static Pet[] pets(){
return new Pet[]{
new Pet(1,"perro1","dog",1),
new Pet(2,"perro2","dog",2),
new Pet(3,"perro3","dog",3),
new Pet(4,"perro4","dog",4),
new Pet(5,"perro5","dog",5),
new Pet(6,"perro6","dog",6),
new Pet(7,"perro7","dog",7),
new Pet(8,"perro8","dog",8),
new Pet(9,"perro9","dog",9),
new Pet(10,"perro10","dog",10)
};
}
public static Pet[] petsWithout(int ... ids) {
Arrays.sort(ids);
final Predicate<Pet> hasValidId = pet ->
binarySearch(ids, pet.getId()) < 0;
return stream(pets())
.filter(hasValidId)
.toArray(Pet[]::new);
}
public static Pet pet(int id) {
return stream(pets())
.filter(pet -> pet.getId() == id)
.findAny()
.orElseThrow(IllegalArgumentException::new);
}
public static int existentId() {
return 5;
}
public static int existentOwner(){
return 5;
}
public static int nonExistentId() {
return 1234;
}
public static Pet existentPet() {
return pet(existentId());
}
public static Pet nonExistentPet() {
return new Pet(nonExistentId(), "perro1", "dog",1);
}
public static String newName() {
return "perro11";
}
public static String newType() {
return "dog";
}
public static int newPerson() {
return 11;
}
public static Pet newPet() {
return new Pet(pets().length + 1, newName(), newType(),newPerson());
}
}
package es.uvigo.esei.daa.entities;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Warning;
public class PetUnitTest {
@Test
public void testPetIntStringStringInt(){
final int id = 1;
final String name = "Boby";
final String type = "dog";
final int person = 1;
final Pet pet = new Pet(id,name,type,person);
assertThat(pet.getId(),is(equalTo(id)));
assertThat(pet.getName(),is(equalTo(name)));
assertThat(pet.getType(),is(equalTo(type)));
assertThat(pet.getPerson(),is(equalTo(person)));
}
@Test(expected = NullPointerException.class)
public void testPetIntStringStringIntNullName() {
new Pet(1, null, "dog",1);
}
@Test(expected = NullPointerException.class)
public void testPetIntStringStringIntNullType() {
new Pet(1, "Boby", null,1);
}
@Test(expected = NullPointerException.class)
public void testPetIntStringStringIntNullPerson() {
Integer person = null;
new Pet(1, "John", "dog",person);
}
@Test
public void testSetName() {
final int id = 1;
final String type = "Dog";
final Pet pet = new Pet(id, "Boby", type,id);
pet.setName("Juan");
assertThat(pet.getId(), is(equalTo(id)));
assertThat(pet.getName(), is(equalTo("Juan")));
assertThat(pet.getType(), is(equalTo(type)));
}
@Test(expected = NullPointerException.class)
public void testSetNullType() {
final Pet pet = new Pet(1, "Boby", "Dog",1);
pet.setType(null);
}
@Test
public void testEqualsObject() {
final Pet petA = new Pet(1, "Name A", "Surname A",1);
final Pet petB = new Pet(1, "Name B", "Surname B",1);
assertTrue(petA.equals(petB));
}
@Test
public void testEqualsHashcode() {
EqualsVerifier.forClass(Pet.class)
.withIgnoredFields("name", "type", "person")
.suppress(Warning.STRICT_INHERITANCE)
.suppress(Warning.NONFINAL_FIELDS)
.verify();
}
}
......@@ -59,6 +59,11 @@ public class AuthorizationFilter implements ContainerRequestFilter {
} else {
requestContext.setSecurityContext(new UserSecurityContext(user));
}
if (isPetsPath(requestContext) && !user.getRole().equals("ADMIN")) {
requestContext.abortWith(createResponse());
} else {
requestContext.setSecurityContext(new UserSecurityContext(user));
}
} else {
requestContext.abortWith(createResponse());
}
......@@ -75,6 +80,11 @@ public class AuthorizationFilter implements ContainerRequestFilter {
final List<PathSegment> pathSegments = context.getUriInfo().getPathSegments();
return !pathSegments.isEmpty() && pathSegments.get(0).getPath().equals("people");
}
private static boolean isPetsPath(ContainerRequestContext context) {
final List<PathSegment> pathSegments = context.getUriInfo().getPathSegments();
return !pathSegments.isEmpty() && pathSegments.get(0).getPath().equals("pets");
}
private static Response createResponse() {
return Response.status(Status.UNAUTHORIZED)
......
package es.uvigo.esei.daa.matchers;
import es.uvigo.esei.daa.entities.Pet;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
public class IsEqualToPet extends IsEqualToEntity<Pet> {
public IsEqualToPet(Pet entity) {
super(entity);
}
@Override
protected boolean matchesSafely(Pet actual) {
this.clearDescribeTo();
if (actual == null) {
this.addTemplatedDescription("actual", expected.toString());
return false;
} else {
return checkAttribute("id", Pet::getId, actual)
&& checkAttribute("name", Pet::getName, actual)
&& checkAttribute("type", Pet::getType, actual)
&& checkAttribute("person", Pet::getPerson, actual);
}
}
/**
* Factory method that creates a new {@link IsEqualToEntity} matcher with
* the provided {@link Pet} as the expected value.
*
* @param Pet the expected pet.
* @return a new {@link IsEqualToEntity} matcher with the provided
* {@link Pet} as the expected value.
*/
@Factory
public static IsEqualToPet equalsToPet(Pet Pet) {
return new IsEqualToPet(Pet);
}
/**
* Factory method that returns a new {@link Matcher} that includes several
* {@link IsEqualToPet} matchers, each one using an {@link Pet} of the
* provided ones as the expected value.
*
* @param pets the pets to be used as the expected values.
* @return a new {@link Matcher} that includes several
* {@link IsEqualToPet} matchers, each one using an {@link Pet} of the
* provided ones as the expected value.
* @see IsEqualToEntity#containsEntityInAnyOrder(java.util.function.Function, Object...)
*/
@Factory
public static Matcher<Iterable<? extends Pet>> containsPetsInAnyOrder(Pet ... pets) {
return containsEntityInAnyOrder(IsEqualToPet::equalsToPet, pets);
}
}
......@@ -97,9 +97,12 @@ public class PeopleResourceTest extends JerseyTest {
@Test
public void testListUnauthorized() throws IOException {
final Response response = target("people").request()
.header("Authorization", "Basic " + userToken(normalLogin()))
.get();
assertThat(response, hasUnauthorized());
}
......
package es.uvigo.esei.daa.rest;
import static es.uvigo.esei.daa.dataset.PetsDataset.*;
import static es.uvigo.esei.daa.dataset.UsersDataset.adminLogin;
import static es.uvigo.esei.daa.dataset.UsersDataset.normalLogin;
import static es.uvigo.esei.daa.dataset.UsersDataset.userToken;
import static es.uvigo.esei.daa.matchers.HasHttpStatus.hasBadRequestStatus;
import static es.uvigo.esei.daa.matchers.HasHttpStatus.hasOkStatus;
import static es.uvigo.esei.daa.matchers.HasHttpStatus.hasUnauthorized;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.equalsToPet;
import static javax.ws.rs.client.Entity.entity;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.util.List;
import javax.sql.DataSource;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import es.uvigo.esei.daa.entities.Pet;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import es.uvigo.esei.daa.DAAExampleTestApplication;
import es.uvigo.esei.daa.listeners.ApplicationContextBinding;
import es.uvigo.esei.daa.listeners.ApplicationContextJndiBindingTestExecutionListener;
import es.uvigo.esei.daa.listeners.DbManagement;
import es.uvigo.esei.daa.listeners.DbManagementTestExecutionListener;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:contexts/mem-context.xml")
@TestExecutionListeners({
DbUnitTestExecutionListener.class,
DbManagementTestExecutionListener.class,
ApplicationContextJndiBindingTestExecutionListener.class
})
@ApplicationContextBinding(
jndiUrl = "java:/comp/env/jdbc/daaexample",
type = DataSource.class
)
@DbManagement(
create = "classpath:db/hsqldb.sql",
drop = "classpath:db/hsqldb-drop.sql"
)
@DatabaseSetup("/datasets/dataset-pet.xml")
@ExpectedDatabase("/datasets/dataset-pet.xml")
public class PetsResourceTest extends JerseyTest {
@Override
protected Application configure() {
return new DAAExampleTestApplication();
}
@Override
protected void configureClient(ClientConfig config) {
super.configureClient(config);
// Enables JSON transformation in client
config.register(JacksonJsonProvider.class);
config.property("com.sun.jersey.api.json.POJOMappingFeature", Boolean.TRUE);
}
@Test
public void testList() throws IOException {
final Response response = target("pets").request()
.header("Authorization", "Basic " + userToken(adminLogin()))
.get();
assertThat(response, hasOkStatus());
final List<Pet> pet = response.readEntity(new GenericType<List<Pet>>(){});
assertThat(pet, containsPetsInAnyOrder(pets()));
}
@Test
public void testListUnauthorized() throws IOException {
final Response response = target("pets").request()
.header("Authorization", "Basic " + userToken(normalLogin()))
.get();
assertThat(response, hasUnauthorized());
}
@Test
public void testGet() throws IOException {
final Response response = target("pets/" + existentId()).request()
.header("Authorization", "Basic " + userToken(adminLogin()))
.get();
assertThat(response, hasOkStatus());
final Pet pet = response.readEntity(Pet.class);
assertThat(pet, is(equalsToPet(existentPet())));
}
@Test
public void testGetUnauthorized() throws IOException {
final Response response = target("pets/" + existentId()).request()
.header("Authorization", "Basic " + userToken(normalLogin()))
.get();
assertThat(response, hasUnauthorized());
}
@Test
public void testGetInvalidId() throws IOException {
final Response response = target("pets/" + nonExistentId()).request()
.header("Authorization", "Basic " + userToken(adminLogin()))
.get();
assertThat(response, hasBadRequestStatus());
}
@Test
@ExpectedDatabase("/datasets/dataset-pet-add.xml")
public void testAdd() throws IOException {
final Form form = new Form();
form.param("name", newName());
form.param("type", newType());
form.param("person", String.valueOf(newPerson()));
final Response response = target("pets").request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasOkStatus());
final Pet pet = response.readEntity(Pet.class);
System.out.println(pet.getId());
System.out.println(newPet().getId());
System.out.println();
assertThat(pet, is(equalsToPet(newPet())));
}
@Test
public void testAddUnauthorized() throws IOException {
final Form form = new Form();
form.param("name", newName());
form.param("type", newType());
form.param("person", String.valueOf(newPerson()));
final Response response = target("pets").request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(normalLogin()))
.post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasUnauthorized());
}
@Test
public void testAddMissingName() throws IOException {
final Form form = new Form();
form.param("type", newType());
form.param("person",String.valueOf(newPerson()));
final Response response = target("pets").request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasBadRequestStatus());
}
@Test
public void testAddMissingType() throws IOException {
final Form form = new Form();
form.param("name", newName());
form.param("type",newType());
final Response response = target("pets").request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasBadRequestStatus());
}
@Test
public void testAddMissingPerson() throws IOException {
final Form form = new Form();
form.param("name", newName());
form.param("type",newType());
final Response response = target("pets").request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.post(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasBadRequestStatus());
}
@Test
@ExpectedDatabase("/datasets/dataset-pet-modify.xml")
public void testModify() throws IOException {
final Form form = new Form();
form.param("name", newName());
form.param("type", newType());
form.param("person",String.valueOf(newPerson()));
final Response response = target("pets/" + existentId()).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasOkStatus());
final Pet modifiedPet = response.readEntity(Pet.class);
final Pet pet = existentPet();
pet.setName(newName());
pet.setType(newType());
pet.setPerson(newPerson());
assertThat(modifiedPet, is(equalsToPet(pet)));
}
@Test
public void testModifyUnauthorized() throws IOException {
final Form form = new Form();
form.param("name", newName());
form.param("type", newType());
form.param("person",String.valueOf(newPerson()));
final Response response = target("pets/" + existentId()).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(normalLogin()))
.put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasUnauthorized());
}
@Test
public void testModifyName() throws IOException {
final Form form = new Form();
form.param("name", newName());
final Response response = target("pets/" + existentId()).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasBadRequestStatus());
}
@Test
public void testModifySurname() throws IOException {
final Form form = new Form();
form.param("type", newType());
final Response response = target("pets/" + existentId()).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasBadRequestStatus());
}
@Test
public void testModifyPerson() throws IOException {
final Form form = new Form();
form.param("person", String.valueOf(newPerson()));
final Response response = target("pets/" + existentId()).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.put(entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasBadRequestStatus());
}
@Test
public void testModifyInvalidId() throws IOException {
final Form form = new Form();
form.param("name", newName());
form.param("type", newType());
form.param("person",String.valueOf(newPerson()));
final Response response = target("pets/" + nonExistentId()).request(MediaType.APPLICATION_JSON_TYPE)
.header("Authorization", "Basic " + userToken(adminLogin()))
.put(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
assertThat(response, hasBadRequestStatus());
}
@Test
@ExpectedDatabase("/datasets/dataset-pet-delete.xml")
public void testDelete() throws IOException {
final Response response = target("pets/" + existentId()).request()
.header("Authorization", "Basic " + userToken(adminLogin()))
.delete();
assertThat(response, hasOkStatus());
final Integer deletedId = response.readEntity(Integer.class);
assertThat(deletedId, is(equalTo(existentId())));
}
@Test
public void testDeleteUnauthorized() throws IOException {
final Response response = target("pets/" + existentId()).request()
.header("Authorization", "Basic " + userToken(normalLogin()))
.delete();
assertThat(response, hasUnauthorized());
}
@Test
public void testDeleteInvalidId() throws IOException {
final Response response = target("pets/" + nonExistentId()).request()
.header("Authorization", "Basic " + userToken(adminLogin()))
.delete();
assertThat(response, hasBadRequestStatus());
}
}
package es.uvigo.esei.daa.rest;
import es.uvigo.esei.daa.dao.DAOException;
import es.uvigo.esei.daa.dao.PetDAO;
import es.uvigo.esei.daa.entities.PersonUnitTest;
import es.uvigo.esei.daa.entities.Pet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.ws.rs.core.Response;
import java.util.List;
import static es.uvigo.esei.daa.dataset.PetsDataset.*;
import static es.uvigo.esei.daa.matchers.HasHttpStatus.*;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder;
import static es.uvigo.esei.daa.matchers.IsEqualToPet.equalsToPet;
import static java.util.Arrays.asList;
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.anyString;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class PetsResourceUnitTest {
private PetDAO daoMock;
private PetsResource resource;
@Before
public void setUp() throws Exception{
daoMock = createMock(PetDAO.class);
resource = new PetsResource(daoMock);
}
@After
public void tearDown() throws Exception {
try {
verify(daoMock);
} finally {
daoMock = null;
resource = null;
}
}
@Test
@SuppressWarnings("unchecked")
public void testList() throws Exception {
final List<Pet> pets = asList(pets());
expect(daoMock.list()).andReturn(pets);
replay(daoMock);
final Response response = resource.list(null);
assertThat(response, hasOkStatus());
assertThat((List<Pet>) response.getEntity(), containsPetsInAnyOrder(pets()));
}
@Test
@SuppressWarnings("unchecked")
public void testListPetsPerson() throws Exception {
final List<Pet> pets = asList(pets());
Integer person = existentOwner();
expect(daoMock.listForPeople(person)).andReturn(pets);
replay(daoMock);
final Response response = resource.list(person);
assertThat(response, hasOkStatus());
assertThat((List<Pet>) response.getEntity(), containsPetsInAnyOrder(pets()));
}
@Test
public void testListDAOException() throws Exception {
expect(daoMock.list()).andThrow(new DAOException());
replay(daoMock);
final Response response = resource.list(null);
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testGet() throws Exception {
final Pet pet = existentPet();
expect(daoMock.get(pet.getId())).andReturn(pet);
replay(daoMock);
final Response response = resource.get(pet.getId());
assertThat(response, hasOkStatus());
assertThat((Pet) response.getEntity(), is(equalsToPet(pet)));
}
@Test
public void testGetDAOException() throws Exception {
expect(daoMock.get(anyInt())).andThrow(new DAOException());
replay(daoMock);
final Response response = resource.get(existentId());
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testGetIllegalArgumentException() throws Exception {
expect(daoMock.get(anyInt())).andThrow(new IllegalArgumentException());
replay(daoMock);
final Response response = resource.get(existentId());
assertThat(response, hasBadRequestStatus());
}
@Test
public void testDelete() throws Exception {
daoMock.delete(anyInt());
replay(daoMock);
final Response response = resource.delete(1);
assertThat(response, hasOkStatus());
}
@Test
public void testDeleteDAOException() throws Exception {
daoMock.delete(anyInt());
expectLastCall().andThrow(new DAOException());
replay(daoMock);
final Response response = resource.delete(1);
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testDeleteIllegalArgumentException() throws Exception {
daoMock.delete(anyInt());
expectLastCall().andThrow(new IllegalArgumentException());
replay(daoMock);
final Response response = resource.delete(1);
assertThat(response, hasBadRequestStatus());
}
@Test
public void testModify() throws Exception {
final Pet pet = existentPet();
pet.setName(newName());
pet.setType(newType());
pet.setPerson(newPerson());
daoMock.modify(pet);
replay(daoMock);
final Response response = resource.modify(
pet.getId(), pet.getName(), pet.getType(),pet.getPerson());
assertThat(response, hasOkStatus());
assertEquals(pet, response.getEntity());
}
@Test
public void testModifyDAOException() throws Exception {
daoMock.modify(anyObject());
expectLastCall().andThrow(new DAOException());
replay(daoMock);
final Response response = resource.modify(existentId(), newName(), newType(),newPerson());
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testModifyIllegalArgumentException() throws Exception {
daoMock.modify(anyObject());
expectLastCall().andThrow(new IllegalArgumentException());
replay(daoMock);
final Response response = resource.modify(existentId(), newName(), newType(),newPerson());
assertThat(response, hasBadRequestStatus());
}
@Test
public void testModifyNullPointerException() throws Exception {
daoMock.modify(anyObject());
expectLastCall().andThrow(new NullPointerException());
replay(daoMock);
final Response response = resource.modify(existentId(), newName(), newType(),newPerson());
assertThat(response, hasBadRequestStatus());
}
@Test
public void testAdd() throws Exception {
expect(daoMock.add(newName(), newType(),newPerson()))
.andReturn(newPet());
replay(daoMock);
final Response response = resource.add(newName(), newType(),newPerson());
assertThat(response, hasOkStatus());
assertThat((Pet) response.getEntity(), is(equalsToPet(newPet())));
}
@Test
public void testAddDAOException() throws Exception {
expect(daoMock.add(anyString(), anyString(),anyInt()))
.andThrow(new DAOException());
replay(daoMock);
final Response response = resource.add(newName(), newType(),newPerson());
assertThat(response, hasInternalServerErrorStatus());
}
@Test
public void testAddIllegalArgumentException() throws Exception {
expect(daoMock.add(anyString(), anyString(),anyInt()))
.andThrow(new IllegalArgumentException());
replay(daoMock);
final Response response = resource.add(newName(), newType(),newPerson());
assertThat(response, hasBadRequestStatus());
}
}
package es.uvigo.esei.daa.suites;
import es.uvigo.esei.daa.dao.PetsDAOTest;
import es.uvigo.esei.daa.rest.PetsResourceTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
......@@ -9,9 +11,11 @@ import es.uvigo.esei.daa.rest.PeopleResourceTest;
import es.uvigo.esei.daa.rest.UsersResourceTest;
@SuiteClasses({
PeopleDAOTest.class,
PeopleResourceTest.class,
UsersResourceTest.class
PeopleDAOTest.class,
PetsResourceTest.class,
PeopleResourceTest.class,
PetsDAOTest.class,
UsersResourceTest.class
})
@RunWith(Suite.class)
public class IntegrationTestSuite {
......
package es.uvigo.esei.daa.suites;
import es.uvigo.esei.daa.dao.PetsDAOUnitTest;
import es.uvigo.esei.daa.entities.PetUnitTest;
import es.uvigo.esei.daa.rest.PetsResourceUnitTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
......@@ -9,9 +12,12 @@ import es.uvigo.esei.daa.entities.PersonUnitTest;
import es.uvigo.esei.daa.rest.PeopleResourceUnitTest;
@SuiteClasses({
PersonUnitTest.class,
PeopleDAOUnitTest.class,
PeopleResourceUnitTest.class
PersonUnitTest.class,
PetUnitTest.class,
PeopleDAOUnitTest.class,
PetsDAOUnitTest.class,
PeopleResourceUnitTest.class,
PetsResourceUnitTest.class
})
@RunWith(Suite.class)
public class UnitTestSuite {
......
......@@ -14,6 +14,17 @@
<people id="10" name="Juan" surname="Jiménez" />
<people id="11" name="John" surname="Doe" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="5" name="perro11" type="dog" person="11"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
......@@ -12,6 +12,17 @@
<people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="5" name="perro11" type="dog" person="11"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
......@@ -13,6 +13,17 @@
<people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="5" name="perro11" type="dog" person="11"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dataset SYSTEM "dataset.dtd">
<dataset>
<people id="1" name="Antón" surname="Álvarez" />
<people id="2" name="Ana" surname="Amargo" />
<people id="3" name="Manuel" surname="Martínez" />
<people id="4" name="María" surname="Márquez" />
<people id="5" name="Lorenzo" surname="López" />
<people id="6" name="Laura" surname="Laredo" />
<people id="7" name="Perico" surname="Palotes" />
<people id="8" name="Patricia" surname="Pérez" />
<people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="5" name="perro5" type="dog" person="5"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<pets id="11" name="perro11" type="dog" person="11"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dataset SYSTEM "dataset.dtd">
<dataset>
<people id="1" name="Antón" surname="Álvarez" />
<people id="2" name="Ana" surname="Amargo" />
<people id="3" name="Manuel" surname="Martínez" />
<people id="4" name="María" surname="Márquez" />
<people id="5" name="Lorenzo" surname="López" />
<people id="6" name="Laura" surname="Laredo" />
<people id="7" name="Perico" surname="Palotes" />
<people id="8" name="Patricia" surname="Pérez" />
<people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dataset SYSTEM "dataset.dtd">
<dataset>
<people id="1" name="Antón" surname="Álvarez" />
<people id="2" name="Ana" surname="Amargo" />
<people id="3" name="Manuel" surname="Martínez" />
<people id="4" name="María" surname="Márquez" />
<people id="5" name="Lorenzo" surname="López" />
<people id="6" name="Laura" surname="Laredo" />
<people id="7" name="Perico" surname="Palotes" />
<people id="8" name="Patricia" surname="Pérez" />
<people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="5" name="perro11" type="dog" person="11"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dataset SYSTEM "dataset.dtd">
<dataset>
<people id="1" name="Antón" surname="Álvarez" />
<people id="2" name="Ana" surname="Amargo" />
<people id="3" name="Manuel" surname="Martínez" />
<people id="4" name="María" surname="Márquez" />
<people id="5" name="Lorenzo" surname="López" />
<people id="6" name="Laura" surname="Laredo" />
<people id="7" name="Perico" surname="Palotes" />
<people id="8" name="Patricia" surname="Pérez" />
<people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="5" name="perro5" type="dog" person="5"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT dataset (people*, users*)>
<!ELEMENT dataset (people*, users*, pets*)>
<!ELEMENT people EMPTY>
<!ELEMENT users EMPTY>
<!ELEMENT pets EMPTY>
<!ATTLIST people
id CDATA #IMPLIED
name CDATA #IMPLIED
......@@ -12,3 +13,9 @@
password CDATA #IMPLIED
role CDATA #IMPLIED
>
<!ATTLIST pets
id CDATA #IMPLIED
name CDATA #IMPLIED
type CDATA #IMPLIED
person CDATA #IMPLIED
>
\ No newline at end of file
......@@ -13,6 +13,17 @@
<people id="9" name="Julia" surname="Justa" />
<people id="10" name="Juan" surname="Jiménez" />
<pets id="1" name="perro1" type="dog" person="1"/>
<pets id="2" name="perro2" type="dog" person="2"/>
<pets id="3" name="perro3" type="dog" person="3"/>
<pets id="4" name="perro4" type="dog" person="4"/>
<pets id="5" name="perro11" type="dog" person="11"/>
<pets id="6" name="perro6" type="dog" person="6"/>
<pets id="7" name="perro7" type="dog" person="7"/>
<pets id="8" name="perro8" type="dog" person="8"/>
<pets id="9" name="perro9" type="dog" person="9"/>
<pets id="10" name="perro10" type="dog" person="10"/>
<users login="admin" password="713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca" role="ADMIN"/>
<users login="normal" password="7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83" role="USER" />
</dataset>
\ No newline at end of file
DROP TABLE People IF EXISTS;
DROP TABLE Users IF EXISTS;
DROP TABLE Pets IF EXISTS;
......@@ -10,4 +10,12 @@ CREATE TABLE users (
password VARCHAR(64) NOT NULL,
role VARCHAR(5) NOT NULL,
PRIMARY KEY (login)
);
\ No newline at end of file
);
CREATE TABLE pets(
id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL,
name VARCHAR(50) NOT NULL,
type VARCHAR(50) NOT NULL,
person int NOT NULL,
PRIMARY KEY (id)
)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment