From ee75950ac67f75752b53d90ffabd862dfbb68b53 Mon Sep 17 00:00:00 2001 From: miferreiro Date: Thu, 21 Feb 2019 18:21:28 +0100 Subject: [PATCH] The integration tests for rest resources of pets and the DAO have been created The files that contain the information to handle the integration tests have been created. --- .../es/uvigo/esei/daa/dao/PetsDAOTest.java | 146 ++++++++ .../uvigo/esei/daa/rest/PetsResourceTest.java | 330 ++++++++++++++++++ .../esei/daa/suites/IntegrationTestSuite.java | 6 + .../resources/datasets/dataset-add-pets.xml | 31 ++ src/test/resources/datasets/dataset-add.xml | 12 + .../datasets/dataset-delete-pets.xml | 29 ++ .../resources/datasets/dataset-delete.xml | 12 + .../datasets/dataset-modify-pets.xml | 30 ++ .../resources/datasets/dataset-modify.xml | 12 + src/test/resources/datasets/dataset.dtd | 9 +- src/test/resources/datasets/dataset.xml | 12 + src/test/resources/db/hsqldb-drop.sql | 2 + src/test/resources/db/hsqldb.sql | 9 + 13 files changed, 639 insertions(+), 1 deletion(-) create mode 100644 src/test/java/es/uvigo/esei/daa/dao/PetsDAOTest.java create mode 100644 src/test/java/es/uvigo/esei/daa/rest/PetsResourceTest.java create mode 100644 src/test/resources/datasets/dataset-add-pets.xml create mode 100644 src/test/resources/datasets/dataset-delete-pets.xml create mode 100644 src/test/resources/datasets/dataset-modify-pets.xml diff --git a/src/test/java/es/uvigo/esei/daa/dao/PetsDAOTest.java b/src/test/java/es/uvigo/esei/daa/dao/PetsDAOTest.java new file mode 100644 index 0000000..713213c --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/dao/PetsDAOTest.java @@ -0,0 +1,146 @@ +package es.uvigo.esei.daa.dao; + +import static es.uvigo.esei.daa.dataset.PetsDataset.existentId; +import static es.uvigo.esei.daa.dataset.PetsDataset.existentIdOwner; +import static es.uvigo.esei.daa.dataset.PetsDataset.existentPet; +import static es.uvigo.esei.daa.dataset.PetsDataset.newName; +import static es.uvigo.esei.daa.dataset.PetsDataset.newPet; +import static es.uvigo.esei.daa.dataset.PetsDataset.newSpecie; +import static es.uvigo.esei.daa.dataset.PetsDataset.newIdOwner; +import static es.uvigo.esei.daa.dataset.PetsDataset.nonExistentId; +import static es.uvigo.esei.daa.dataset.PetsDataset.nonExistentIdOwner; +import static es.uvigo.esei.daa.dataset.PetsDataset.nonExistentPet; +import static es.uvigo.esei.daa.dataset.PetsDataset.pets; +import static es.uvigo.esei.daa.dataset.PetsDataset.petsOwner; +import static es.uvigo.esei.daa.dataset.PetsDataset.petsWithout; +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 javax.sql.DataSource; + +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 com.github.springtestdbunit.DbUnitTestExecutionListener; +import com.github.springtestdbunit.annotation.DatabaseSetup; +import com.github.springtestdbunit.annotation.ExpectedDatabase; + +import es.uvigo.esei.daa.entities.Pet; +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.xml") +@ExpectedDatabase("/datasets/dataset.xml") +public class PetsDAOTest { + private PetsDAO dao; + + @Before + public void setUp() throws Exception { + this.dao = new PetsDAO(); + } + + @Test + public void testList() throws DAOException { + assertThat(this.dao.list(), containsPetsInAnyOrder(pets())); + } + + @Test + public void testGetPets() throws DAOException { + assertThat(this.dao.getPets(existentIdOwner()), containsPetsInAnyOrder(petsOwner(existentIdOwner()))); + } + + @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-delete-pets.xml") + public void testDelete() throws DAOException { + this.dao.delete(existentId()); + + assertThat(this.dao.list(), containsPetsInAnyOrder(petsWithout(existentId()))); + } + + @Test(expected = IllegalArgumentException.class) + public void testDeleteNonExistentId() throws DAOException { + this.dao.delete(nonExistentId()); + } + + @Test + @ExpectedDatabase("/datasets/dataset-modify-pets.xml") + public void testModify() throws DAOException { + final Pet pet = existentPet(); + pet.setName(newName()); + pet.setSpecie(newSpecie()); + pet.setIdOwner(newIdOwner()); + + this.dao.modify(pet); + + final Pet persistentPet = this.dao.get(pet.getId()); + + assertThat(persistentPet, is(equalsToPet(pet))); + } + + @Test(expected = IllegalArgumentException.class) + public void testModifyNonExistentId() throws DAOException { + this.dao.modify(nonExistentPet()); + } + + @Test(expected = IllegalArgumentException.class) + public void testModifyNullPerson() throws DAOException { + this.dao.modify(null); + } + + @Test + @ExpectedDatabase("/datasets/dataset-add-pets.xml") + public void testAdd() throws DAOException { + final Pet pet = this.dao.add(newName(), newSpecie(), newIdOwner()); + + 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, newSpecie(), newIdOwner()); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddNullSurname() throws DAOException { + this.dao.add(newName(), null, newIdOwner()); + } +} diff --git a/src/test/java/es/uvigo/esei/daa/rest/PetsResourceTest.java b/src/test/java/es/uvigo/esei/daa/rest/PetsResourceTest.java new file mode 100644 index 0000000..b29aa84 --- /dev/null +++ b/src/test/java/es/uvigo/esei/daa/rest/PetsResourceTest.java @@ -0,0 +1,330 @@ +package es.uvigo.esei.daa.rest; + +import static es.uvigo.esei.daa.dataset.PetsDataset.newName; +import static es.uvigo.esei.daa.dataset.PetsDataset.newPet; +import static es.uvigo.esei.daa.dataset.PetsDataset.newSpecie; +import static es.uvigo.esei.daa.dataset.PetsDataset.newIdOwner; +import static es.uvigo.esei.daa.dataset.PetsDataset.nonExistentId; +import static es.uvigo.esei.daa.dataset.PetsDataset.existentId; +import static es.uvigo.esei.daa.dataset.PetsDataset.existentIdOwner; +import static es.uvigo.esei.daa.dataset.PetsDataset.existentPet; +import static es.uvigo.esei.daa.dataset.PetsDataset.pets; +import static es.uvigo.esei.daa.dataset.PetsDataset.petsOwner; +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.equalsToPet; +import static javax.ws.rs.client.Entity.entity; +import static es.uvigo.esei.daa.matchers.IsEqualToPet.containsPetsInAnyOrder; +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.Arrays; +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 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.entities.Pet; +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.xml") +@ExpectedDatabase("/datasets/dataset.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 pets = response.readEntity(new GenericType>(){}); + + assertThat(pets, 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 testListOwner() throws IOException { + + final Response response = target("pets").queryParam("idOwner", existentIdOwner()).request() + .header("Authorization", "Basic " + userToken(adminLogin())) + .get(); + assertThat(response, hasOkStatus()); + + final List pets = response.readEntity(new GenericType>(){}); + + assertThat(pets, containsPetsInAnyOrder(petsOwner(existentIdOwner()))); + } + + @Test + public void testListOwnerUnauthorized() throws IOException { + final Response response = target("pets").queryParam("idOwner", existentIdOwner()).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-add-pets.xml") + public void testAdd() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + form.param("specie", newSpecie()); + form.param("idOwner", Integer.toString(newIdOwner())); + + 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); + + assertThat(pet, is(equalsToPet(newPet()))); + } + + @Test + public void testAddUnauthorized() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + form.param("specie", newSpecie()); + form.param("idOwner", Integer.toString(newIdOwner())); + + 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("specie", newSpecie()); + form.param("idOwner", Integer.toString(newIdOwner())); + + 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 testAddMissingSpecie() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + form.param("idOwner", Integer.toString(newIdOwner())); + + 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-modify-pets.xml") + public void testModify() throws IOException { + final Form form = new Form(); + + form.param("name", newName()); + + form.param("specie", newSpecie()); + + form.param("idOwner",Integer.toString(newIdOwner())); + + 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.setSpecie(newSpecie()); + pet.setIdOwner(newIdOwner()); + + assertThat(modifiedPet, is(equalsToPet(pet))); + } + + @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 testModifyUnauthorized() throws IOException { + final Form form = new Form(); + form.param("name", newName()); + form.param("surname", newSpecie()); + form.param("idOwner", Integer.toString(newIdOwner())); + + 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 testModifySpecie() throws IOException { + final Form form = new Form(); + form.param("specie", newSpecie()); + form.param("idOwner", Integer.toString(newIdOwner())); + + 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("specie", newSpecie()); + form.param("idOwner", Integer.toString(newIdOwner())); + + 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-delete-pets.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()); + } + +} diff --git a/src/test/java/es/uvigo/esei/daa/suites/IntegrationTestSuite.java b/src/test/java/es/uvigo/esei/daa/suites/IntegrationTestSuite.java index 822c83f..49b204b 100644 --- a/src/test/java/es/uvigo/esei/daa/suites/IntegrationTestSuite.java +++ b/src/test/java/es/uvigo/esei/daa/suites/IntegrationTestSuite.java @@ -5,12 +5,18 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; import es.uvigo.esei.daa.dao.PeopleDAOTest; +import es.uvigo.esei.daa.dao.PetsDAOTest; import es.uvigo.esei.daa.rest.PeopleResourceTest; +import es.uvigo.esei.daa.rest.PetsResourceTest; import es.uvigo.esei.daa.rest.UsersResourceTest; @SuiteClasses({ + PeopleDAOTest.class, + PetsDAOTest.class, + PeopleResourceTest.class, + PetsResourceTest.class, UsersResourceTest.class }) @RunWith(Suite.class) diff --git a/src/test/resources/datasets/dataset-add-pets.xml b/src/test/resources/datasets/dataset-add-pets.xml new file mode 100644 index 0000000..7d8d2c3 --- /dev/null +++ b/src/test/resources/datasets/dataset-add-pets.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset-add.xml b/src/test/resources/datasets/dataset-add.xml index 9a75a99..088fb6d 100644 --- a/src/test/resources/datasets/dataset-add.xml +++ b/src/test/resources/datasets/dataset-add.xml @@ -16,4 +16,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset-delete-pets.xml b/src/test/resources/datasets/dataset-delete-pets.xml new file mode 100644 index 0000000..2b9ac6f --- /dev/null +++ b/src/test/resources/datasets/dataset-delete-pets.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset-delete.xml b/src/test/resources/datasets/dataset-delete.xml index e49223d..4491087 100644 --- a/src/test/resources/datasets/dataset-delete.xml +++ b/src/test/resources/datasets/dataset-delete.xml @@ -14,4 +14,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset-modify-pets.xml b/src/test/resources/datasets/dataset-modify-pets.xml new file mode 100644 index 0000000..8976f01 --- /dev/null +++ b/src/test/resources/datasets/dataset-modify-pets.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset-modify.xml b/src/test/resources/datasets/dataset-modify.xml index 6e2dfc9..91cc03e 100644 --- a/src/test/resources/datasets/dataset-modify.xml +++ b/src/test/resources/datasets/dataset-modify.xml @@ -15,4 +15,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset.dtd b/src/test/resources/datasets/dataset.dtd index e64500f..4553f6a 100644 --- a/src/test/resources/datasets/dataset.dtd +++ b/src/test/resources/datasets/dataset.dtd @@ -1,7 +1,8 @@ - + + + \ No newline at end of file diff --git a/src/test/resources/datasets/dataset.xml b/src/test/resources/datasets/dataset.xml index 3f48cc9..b1793b5 100644 --- a/src/test/resources/datasets/dataset.xml +++ b/src/test/resources/datasets/dataset.xml @@ -15,4 +15,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/db/hsqldb-drop.sql b/src/test/resources/db/hsqldb-drop.sql index 31f8643..18f5517 100644 --- a/src/test/resources/db/hsqldb-drop.sql +++ b/src/test/resources/db/hsqldb-drop.sql @@ -1,2 +1,4 @@ +DROP TABLE Pets IF EXISTS; DROP TABLE People IF EXISTS; DROP TABLE Users IF EXISTS; + diff --git a/src/test/resources/db/hsqldb.sql b/src/test/resources/db/hsqldb.sql index a629441..a125142 100644 --- a/src/test/resources/db/hsqldb.sql +++ b/src/test/resources/db/hsqldb.sql @@ -10,4 +10,13 @@ CREATE TABLE users ( password VARCHAR(64) NOT NULL, role VARCHAR(5) NOT NULL, PRIMARY KEY (login) +); + +CREATE TABLE pets ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL, + name varchar(50) NOT NULL, + specie varchar(50) NOT NULL, + idOwner int NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (idOwner) REFERENCES people(id) ); \ No newline at end of file -- 2.18.1