adding support to use redis as backend

This commit is contained in:
Kumar 2019-08-28 16:36:24 +05:30
parent d6bdc13bdb
commit 537cbea395
27 changed files with 947 additions and 843 deletions

17
pom.xml
View file

@ -58,6 +58,10 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Databases - Uses HSQL by default --> <!-- Databases - Uses HSQL by default -->
<dependency> <dependency>
@ -207,6 +211,19 @@
</dependency> </dependency>
</dependencies> </dependencies>
</plugin> </plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>1.24.1</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>

View file

@ -8,12 +8,15 @@ Deploy this sample application to Pivotal Web Services:
## Understanding the Spring Petclinic application with a few diagrams ## Understanding the Spring Petclinic application with a few diagrams
<a href="https://speakerdeck.com/michaelisvy/spring-petclinic-sample-application">See the presentation here</a> <a href="https://speakerdeck.com/michaelisvy/spring-petclinic-sample-application">See the presentation here</a>
## Runtime Dependency
This forked version of pet-clinic usages redis as data store. The redis server must be running locally or remotely and configured in application.properties file.
## Running petclinic locally ## Running petclinic locally
Petclinic is a [Spring Boot](https://spring.io/guides/gs/spring-boot) application built using [Maven](https://spring.io/guides/gs/maven/). You can build a jar file and run it from the command line: Petclinic is a [Spring Boot](https://spring.io/guides/gs/spring-boot) application built using [Maven](https://spring.io/guides/gs/maven/). You can build a jar file and run it from the command line:
``` ```
git clone https://github.com/spring-projects/spring-petclinic.git git clone https://github.com/er-satish/spring-petclinic.git
cd spring-petclinic cd spring-petclinic
./mvnw package ./mvnw package
java -jar target/*.jar java -jar target/*.jar
@ -35,17 +38,25 @@ Our issue tracker is available here: https://github.com/spring-projects/spring-p
## Database configuration ## Database configuration
In its default configuration, Petclinic uses an in-memory database (HSQLDB) which In this forked version of pet-clinic, it usages redis as data store. So, the same should be accessible to the application and configured in application properties file.
gets populated at startup with data. A similar setup is provided for MySql in case a persistent database configuration is needed.
Note that whenever the database type is changed, the app needs to be run with a different profile: `spring.profiles.active=mysql` for MySql.
You could start MySql locally with whatever installer works for your OS, or with docker: You could start Redis locally with whatever installer works for your OS, or with d ocker:
``` ```
docker run -e MYSQL_ROOT_PASSWORD=petclinic -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:5.7.8 docker run -d -p 6379:6379 redis
```
check the running container id:
```
docker ps
```
connect to the running container:
```
docker exec -it <container_id> /bin/bash
```
open redis command line interface:
```
redis-cli
``` ```
Further documentation is provided [here](https://github.com/spring-projects/spring-petclinic/blob/master/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt).
## Working with Petclinic in your IDE ## Working with Petclinic in your IDE
@ -120,9 +131,7 @@ Here is a list of them:
# Contributing # Contributing
The [issue tracker](https://github.com/spring-projects/spring-petclinic/issues) is the preferred channel for bug reports, features requests and submitting pull requests. Feel free to raise the pull request for any fixes or enhancements to demonstrate spring-redis capability.
For pull requests, editor preferences are available in the [editor config](.editorconfig) for easy use in common text editors. Read more and download plugins at <https://editorconfig.org>. If you have not previously done so, please fill out and submit the [Contributor License Agreement](https://cla.pivotal.io/sign/spring).
# License # License
@ -138,3 +147,12 @@ The Spring PetClinic sample application is released under version 2.0 of the [Ap
[spring-petclinic-graphql]: https://github.com/spring-petclinic/spring-petclinic-graphql [spring-petclinic-graphql]: https://github.com/spring-petclinic/spring-petclinic-graphql
[spring-petclinic-kotlin]: https://github.com/spring-petclinic/spring-petclinic-kotlin [spring-petclinic-kotlin]: https://github.com/spring-petclinic/spring-petclinic-kotlin
[spring-petclinic-rest]: https://github.com/spring-petclinic/spring-petclinic-rest [spring-petclinic-rest]: https://github.com/spring-petclinic/spring-petclinic-rest
# TODOs
1. Junits fixes
2. Implement the flow for:
a) Edit Pet details
b) Add visit
c) Veterinarians listing
3. Setup CI/CD pipeline

View file

@ -29,10 +29,8 @@ import javax.persistence.MappedSuperclass;
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@MappedSuperclass
public class BaseEntity implements Serializable { public class BaseEntity implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id; private Integer id;
public Integer getId() { public Integer getId() {

View file

@ -26,7 +26,6 @@ import javax.persistence.MappedSuperclass;
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@MappedSuperclass
public class NamedEntity extends BaseEntity { public class NamedEntity extends BaseEntity {
@Column(name = "name") @Column(name = "name")

View file

@ -15,6 +15,8 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import org.springframework.data.redis.core.index.Indexed;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
@ -24,15 +26,13 @@ import javax.validation.constraints.NotEmpty;
* *
* @author Ken Krebs * @author Ken Krebs
*/ */
@MappedSuperclass
public class Person extends BaseEntity { public class Person extends BaseEntity {
@Column(name = "first_name")
@NotEmpty @NotEmpty
private String firstName; private String firstName;
@Column(name = "last_name")
@NotEmpty @NotEmpty
@Indexed
private String lastName; private String lastName;
public String getFirstName() { public String getFirstName() {

View file

@ -32,6 +32,7 @@ import javax.validation.constraints.NotEmpty;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.samples.petclinic.model.Person; import org.springframework.samples.petclinic.model.Person;
/** /**
@ -42,23 +43,18 @@ import org.springframework.samples.petclinic.model.Person;
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
@Entity @RedisHash("owners")
@Table(name = "owners")
public class Owner extends Person { public class Owner extends Person {
@Column(name = "address")
@NotEmpty @NotEmpty
private String address; private String address;
@Column(name = "city")
@NotEmpty @NotEmpty
private String city; private String city;
@Column(name = "telephone")
@NotEmpty @NotEmpty
@Digits(fraction = 0, integer = 10) @Digits(fraction = 0, integer = 10)
private String telephone; private String telephone;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets; private Set<Pet> pets;
public String getAddress() { public String getAddress() {
@ -106,10 +102,16 @@ public class Owner extends Person {
public void addPet(Pet pet) { public void addPet(Pet pet) {
if (pet.isNew()) { if (pet.isNew()) {
getPetsInternal().add(pet); getPetsInternal().add(pet);
}else{
this.pets.add(pet);
} }
pet.setOwner(this); pet.setOwner(this);
} }
public void addPets(List<Pet> pets) {
this.getPetsInternal().addAll(pets);
}
/** /**
* Return the Pet with the given name, or null if none found for this Owner. * Return the Pet with the given name, or null if none found for this Owner.
* *

View file

@ -15,6 +15,8 @@
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
@ -28,6 +30,7 @@ import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Optional;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
@ -38,7 +41,10 @@ import java.util.Map;
@Controller @Controller
class OwnerController { class OwnerController {
private final Logger logger = LoggerFactory.getLogger(OwnerController.class);
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm"; private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private final OwnerRepository owners; private final OwnerRepository owners;
@ -76,7 +82,7 @@ class OwnerController {
@GetMapping("/owners") @GetMapping("/owners")
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) { public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
logger.info("Received request to find owners");
// allow parameterless GET request for /owners to return all records // allow parameterless GET request for /owners to return all records
if (owner.getLastName() == null) { if (owner.getLastName() == null) {
owner.setLastName(""); // empty string signifies broadest possible search owner.setLastName(""); // empty string signifies broadest possible search
@ -84,6 +90,7 @@ class OwnerController {
// find owners by last name // find owners by last name
Collection<Owner> results = this.owners.findByLastName(owner.getLastName()); Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
//Collection<Owner> results = this.owners.findAll();
if (results.isEmpty()) { if (results.isEmpty()) {
// no owners found // no owners found
result.rejectValue("lastName", "notFound", "not found"); result.rejectValue("lastName", "notFound", "not found");
@ -101,7 +108,8 @@ class OwnerController {
@GetMapping("/owners/{ownerId}/edit") @GetMapping("/owners/{ownerId}/edit")
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.owners.findById(ownerId); Optional<Owner> isOwnerFound = this.owners.findById(ownerId);
Owner owner = isOwnerFound.isPresent() ? isOwnerFound.get() : null;
model.addAttribute(owner); model.addAttribute(owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} }
@ -111,7 +119,10 @@ class OwnerController {
if (result.hasErrors()) { if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} else { } else {
Optional<Owner> isOwnerFound = this.owners.findById(ownerId);
Owner ownerFromDb = isOwnerFound.isPresent() ? isOwnerFound.get() : null;
owner.setId(ownerId); owner.setId(ownerId);
owner.addPets(ownerFromDb.getPets());
this.owners.save(owner); this.owners.save(owner);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
@ -126,7 +137,8 @@ class OwnerController {
@GetMapping("/owners/{ownerId}") @GetMapping("/owners/{ownerId}")
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
ModelAndView mav = new ModelAndView("owners/ownerDetails"); ModelAndView mav = new ModelAndView("owners/ownerDetails");
mav.addObject(this.owners.findById(ownerId)); Optional<Owner> isOwnerFound = this.owners.findById(ownerId);
mav.addObject(isOwnerFound.isPresent()? isOwnerFound.get() : null);
return mav; return mav;
} }

View file

@ -16,7 +16,10 @@
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
@ -32,7 +35,10 @@ import org.springframework.transaction.annotation.Transactional;
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface OwnerRepository extends Repository<Owner, Integer> { public interface OwnerRepository extends JpaRepository<Owner, Integer> {
@Override
void deleteById(Integer integer);
/** /**
* Retrieve {@link Owner}s from the data store by last name, returning all owners * Retrieve {@link Owner}s from the data store by last name, returning all owners
@ -41,8 +47,6 @@ public interface OwnerRepository extends Repository<Owner, Integer> {
* @return a Collection of matching {@link Owner}s (or an empty Collection if none * @return a Collection of matching {@link Owner}s (or an empty Collection if none
* found) * found)
*/ */
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
@Transactional(readOnly = true)
Collection<Owner> findByLastName(@Param("lastName") String lastName); Collection<Owner> findByLastName(@Param("lastName") String lastName);
/** /**
@ -50,15 +54,12 @@ public interface OwnerRepository extends Repository<Owner, Integer> {
* @param id the id to search for * @param id the id to search for
* @return the {@link Owner} if found * @return the {@link Owner} if found
*/ */
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") Optional<Owner> findById(@Param("id") Integer id);
@Transactional(readOnly = true)
Owner findById(@Param("id") Integer id);
/** /**
* Save an {@link Owner} to the data store, either inserting or updating it. * Save an {@link Owner} to the data store, either inserting or updating it.
* @param owner the {@link Owner} to save * @param owner the {@link Owner} to save
*/ */
void save(Owner owner); Owner save(Owner owner);
} }

View file

@ -30,10 +30,11 @@ import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.data.annotation.Transient;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.NamedEntity;
import org.springframework.samples.petclinic.visit.Visit; import org.springframework.samples.petclinic.visit.Visit;
@ -45,23 +46,22 @@ import org.springframework.samples.petclinic.visit.Visit;
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
*/ */
@Entity @RedisHash("pets")
@Table(name = "pets")
public class Pet extends NamedEntity { public class Pet extends NamedEntity {
@Column(name = "birth_date")
@DateTimeFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate; private LocalDate birthDate;
@ManyToOne
@JoinColumn(name = "type_id") @JoinColumn(name = "type_id")
private PetType type; private PetType type;
/**
@ManyToOne * Pet need not save Owner to avoid cyclic dependency while persisting.
@JoinColumn(name = "owner_id") */
@Transient
private Owner owner; private Owner owner;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "petId", fetch = FetchType.EAGER) private Integer ownerId;
private Set<Visit> visits = new LinkedHashSet<>(); private Set<Visit> visits = new LinkedHashSet<>();
public void setBirthDate(LocalDate birthDate) { public void setBirthDate(LocalDate birthDate) {
@ -86,6 +86,7 @@ public class Pet extends NamedEntity {
protected void setOwner(Owner owner) { protected void setOwner(Owner owner) {
this.owner = owner; this.owner = owner;
this.ownerId = owner.getId();
} }
protected Set<Visit> getVisitsInternal() { protected Set<Visit> getVisitsInternal() {

View file

@ -15,6 +15,8 @@
*/ */
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -22,8 +24,12 @@ import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.PostConstruct;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Optional;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
@ -33,24 +39,40 @@ import java.util.Collection;
@Controller @Controller
@RequestMapping("/owners/{ownerId}") @RequestMapping("/owners/{ownerId}")
class PetController { class PetController {
private final Logger logger = LoggerFactory.getLogger(PetController.class);
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"; private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
private final PetRepository pets; private final PetRepository pets;
private final OwnerRepository owners; private final OwnerRepository owners;
private final PetTypeRepository petTypes;
public PetController(PetRepository pets, OwnerRepository owners) { @PostConstruct
public void initialize(){
if(this.petTypes.findAll().isEmpty()){
PetType cat = new PetType();
cat.setName("Cat");
PetType dog = new PetType();
dog.setName("Dog");
petTypes.save(cat);
petTypes.save(dog);
logger.info("All pet types saved");
}
}
public PetController(PetRepository pets, OwnerRepository owners,PetTypeRepository petTypes) {
this.pets = pets; this.pets = pets;
this.owners = owners; this.owners = owners;
this.petTypes = petTypes;
} }
@ModelAttribute("types") @ModelAttribute("types")
public Collection<PetType> populatePetTypes() { public Collection<PetType> populatePetTypes() {
return this.pets.findPetTypes(); return this.petTypes.findAll();
} }
@ModelAttribute("owner") @ModelAttribute("owner")
public Owner findOwner(@PathVariable("ownerId") int ownerId) { public Owner findOwner(@PathVariable("ownerId") int ownerId) {
return this.owners.findById(ownerId); Optional<Owner> ownerSearch = this.owners.findById(ownerId);
return ownerSearch.isPresent() ? ownerSearch.get() : null;
} }
@InitBinder("owner") @InitBinder("owner")
@ -81,15 +103,21 @@ class PetController {
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else { } else {
this.pets.save(pet); addPet(owner, pet);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
private void addPet(Owner owner, @Valid Pet pet) {
this.pets.save(pet);
owner.addPet(pet);
owners.save(owner);
}
@GetMapping("/pets/{petId}/edit") @GetMapping("/pets/{petId}/edit")
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) { public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
Pet pet = this.pets.findById(petId); Optional<Pet> petSearch = this.pets.findById(petId);
model.put("pet", pet); model.put("pet", petSearch.isPresent() ? petSearch.get(): null);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} }
@ -100,7 +128,6 @@ class PetController {
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else { } else {
owner.addPet(pet);
this.pets.save(pet); this.pets.save(pet);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }

View file

@ -16,7 +16,9 @@
package org.springframework.samples.petclinic.owner; package org.springframework.samples.petclinic.owner;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -31,15 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface PetRepository extends Repository<Pet, Integer> { public interface PetRepository extends JpaRepository<Pet, Integer> {
/**
* Retrieve all {@link PetType}s from the data store.
* @return a Collection of {@link PetType}s.
*/
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
@Transactional(readOnly = true)
List<PetType> findPetTypes();
/** /**
* Retrieve a {@link Pet} from the data store by id. * Retrieve a {@link Pet} from the data store by id.
@ -47,13 +41,13 @@ public interface PetRepository extends Repository<Pet, Integer> {
* @return the {@link Pet} if found * @return the {@link Pet} if found
*/ */
@Transactional(readOnly = true) @Transactional(readOnly = true)
Pet findById(Integer id); Optional<Pet> findById(Integer id);
/** /**
* Save a {@link Pet} to the data store, either inserting or updating it. * Save a {@link Pet} to the data store, either inserting or updating it.
* @param pet the {@link Pet} to save * @param pet the {@link Pet} to save
*/ */
void save(Pet pet); Pet save(Pet pet);
} }

View file

@ -18,14 +18,14 @@ package org.springframework.samples.petclinic.owner;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.NamedEntity;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* Can be Cat, Dog, Hamster... * Can be Cat, Dog, Hamster...
*/ */
@Entity @RedisHash("petTypes")
@Table(name = "types")
public class PetType extends NamedEntity { public class PetType extends NamedEntity {
} }

View file

@ -36,11 +36,14 @@ import org.springframework.stereotype.Component;
public class PetTypeFormatter implements Formatter<PetType> { public class PetTypeFormatter implements Formatter<PetType> {
private final PetRepository pets; private final PetRepository pets;
private final PetTypeRepository petTypes;
@Autowired @Autowired
public PetTypeFormatter(PetRepository pets) { public PetTypeFormatter(PetRepository pets,PetTypeRepository petTypes) {
this.pets = pets; this.pets = pets;
this.petTypes = petTypes;
} }
@Override @Override
@ -50,7 +53,7 @@ public class PetTypeFormatter implements Formatter<PetType> {
@Override @Override
public PetType parse(String text, Locale locale) throws ParseException { public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = this.pets.findPetTypes(); Collection<PetType> findPetTypes = this.petTypes.findAll();
for (PetType type : findPetTypes) { for (PetType type : findPetTypes) {
if (type.getName().equals(text)) { if (type.getName().equals(text)) {
return type; return type;

View file

@ -0,0 +1,11 @@
package org.springframework.samples.petclinic.owner;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* Repository class for <code>PetType</code> domain object.
* @author er-satish
*/
public interface PetTypeRepository extends JpaRepository<PetType,Integer> {
}

View file

@ -24,6 +24,7 @@ import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Map; import java.util.Map;
import java.util.Optional;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
@ -61,11 +62,16 @@ class VisitController {
*/ */
@ModelAttribute("visit") @ModelAttribute("visit")
public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) { public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
Pet pet = this.pets.findById(petId); Optional<Pet> petSearch = this.pets.findById(petId);
Pet pet = petSearch.isPresent() ? petSearch.get(): null;
model.put("pet", pet); model.put("pet", pet);
Visit visit = new Visit(); if(pet!=null){
pet.addVisit(visit); Visit visit = new Visit();
return visit; pet.addVisit(visit);
return visit;
}
return null;
} }
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called

View file

@ -0,0 +1,28 @@
package org.springframework.samples.petclinic.system;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
/**
* Maintains configuations for using redis as data store.
* @author er-satish
*/
@Configuration
@EnableRedisRepositories
public class RedisConfiguration {
@Bean
public LettuceConnectionFactory redisConnectionFactory(){
return new LettuceConnectionFactory();
}
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
return template;
}
}

View file

@ -20,6 +20,7 @@ import java.io.Serializable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.NamedEntity;
/** /**
@ -27,8 +28,7 @@ import org.springframework.samples.petclinic.model.NamedEntity;
* *
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@Entity @RedisHash("specialties")
@Table(name = "specialties")
public class Specialty extends NamedEntity implements Serializable { public class Specialty extends NamedEntity implements Serializable {
} }

View file

@ -31,6 +31,7 @@ import javax.xml.bind.annotation.XmlElement;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.samples.petclinic.model.Person; import org.springframework.samples.petclinic.model.Person;
/** /**
@ -41,12 +42,9 @@ import org.springframework.samples.petclinic.model.Person;
* @author Sam Brannen * @author Sam Brannen
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
@Entity @RedisHash("vets")
@Table(name = "vets")
public class Vet extends Person { public class Vet extends Person {
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id"))
private Set<Specialty> specialties; private Set<Specialty> specialties;
protected Set<Specialty> getSpecialtiesInternal() { protected Set<Specialty> getSpecialtiesInternal() {

View file

@ -22,6 +22,7 @@ import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
@ -31,11 +32,9 @@ import org.springframework.samples.petclinic.model.BaseEntity;
* @author Ken Krebs * @author Ken Krebs
* @author Dave Syer * @author Dave Syer
*/ */
@Entity @RedisHash
@Table(name = "visits")
public class Visit extends BaseEntity { public class Visit extends BaseEntity {
@Column(name = "visit_date")
@DateTimeFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date; private LocalDate date;
@ -43,7 +42,6 @@ public class Visit extends BaseEntity {
@Column(name = "description") @Column(name = "description")
private String description; private String description;
@Column(name = "pet_id")
private Integer petId; private Integer petId;
/** /**

View file

@ -18,6 +18,7 @@ package org.springframework.samples.petclinic.visit;
import java.util.List; import java.util.List;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
@ -31,7 +32,7 @@ import org.springframework.samples.petclinic.model.BaseEntity;
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface VisitRepository extends Repository<Visit, Integer> { public interface VisitRepository extends JpaRepository<Visit, Integer> {
/** /**
* Save a <code>Visit</code> to the data store, either inserting or updating it. * Save a <code>Visit</code> to the data store, either inserting or updating it.
@ -39,7 +40,7 @@ public interface VisitRepository extends Repository<Visit, Integer> {
* @param visit the <code>Visit</code> to save * @param visit the <code>Visit</code> to save
* @see BaseEntity#isNew * @see BaseEntity#isNew
*/ */
void save(Visit visit) throws DataAccessException; Visit save(Visit visit) throws DataAccessException;
List<Visit> findByPetId(Integer petId); List<Visit> findByPetId(Integer petId);

View file

@ -1,7 +0,0 @@
# database init, supports mysql too
database=mysql
spring.datasource.url=jdbc:mysql://localhost/petclinic
spring.datasource.username=root
spring.datasource.password=petclinic
# Uncomment this the first time the app runs
# spring.datasource.initialization-mode=always

View file

@ -1,14 +1,6 @@
# database init, supports mysql too
database=hsqldb
spring.datasource.schema=classpath*:db/${database}/schema.sql
spring.datasource.data=classpath*:db/${database}/data.sql
# Web # Web
spring.thymeleaf.mode=HTML spring.thymeleaf.mode=HTML
# JPA
spring.jpa.hibernate.ddl-auto=none
# Internationalization # Internationalization
spring.messages.basename=messages/messages spring.messages.basename=messages/messages
@ -23,3 +15,8 @@ logging.level.org.springframework=INFO
# Maximum time static resources should be cached # Maximum time static resources should be cached
spring.resources.cache.cachecontrol.max-age=12h spring.resources.cache.cachecontrol.max-age=12h
# Redis in memory store configuration
spring.redis.host=localhost
spring.redis.port=6379
spring.main.allow-bean-definition-overriding=true

View file

@ -1,195 +1,195 @@
/* ///*
* Copyright 2012-2019 the original author or authors. // * Copyright 2012-2019 the original author or authors.
* // *
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* // *
* https://www.apache.org/licenses/LICENSE-2.0 // * https://www.apache.org/licenses/LICENSE-2.0
* // *
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
//
package org.springframework.samples.petclinic.owner; //package org.springframework.samples.petclinic.owner;
//
import static org.hamcrest.Matchers.hasProperty; //import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is; //import static org.hamcrest.Matchers.is;
import static org.mockito.BDDMockito.given; //import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; //import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; //import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
//
import org.assertj.core.util.Lists; //import org.assertj.core.util.Lists;
import org.junit.Before; //import org.junit.Before;
import org.junit.Test; //import org.junit.Test;
import org.junit.runner.RunWith; //import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; //import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; //import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.samples.petclinic.owner.Owner; //import org.springframework.samples.petclinic.owner.Owner;
import org.springframework.samples.petclinic.owner.OwnerController; //import org.springframework.samples.petclinic.owner.OwnerController;
import org.springframework.samples.petclinic.owner.OwnerRepository; //import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.test.context.junit4.SpringRunner; //import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; //import org.springframework.test.web.servlet.MockMvc;
//
/** ///**
* Test class for {@link OwnerController} // * Test class for {@link OwnerController}
* // *
* @author Colin But // * @author Colin But
*/ // */
@RunWith(SpringRunner.class) //@RunWith(SpringRunner.class)
@WebMvcTest(OwnerController.class) //@WebMvcTest(OwnerController.class)
public class OwnerControllerTests { //public class OwnerControllerTests {
//
private static final int TEST_OWNER_ID = 1; // private static final int TEST_OWNER_ID = 1;
//
@Autowired // @Autowired
private MockMvc mockMvc; // private MockMvc mockMvc;
//
@MockBean // @MockBean
private OwnerRepository owners; // private OwnerRepository owners;
//
private Owner george; // private Owner george;
//
@Before // @Before
public void setup() { // public void setup() {
george = new Owner(); // george = new Owner();
george.setId(TEST_OWNER_ID); // george.setId(TEST_OWNER_ID);
george.setFirstName("George"); // george.setFirstName("George");
george.setLastName("Franklin"); // george.setLastName("Franklin");
george.setAddress("110 W. Liberty St."); // george.setAddress("110 W. Liberty St.");
george.setCity("Madison"); // george.setCity("Madison");
george.setTelephone("6085551023"); // george.setTelephone("6085551023");
given(this.owners.findById(TEST_OWNER_ID)).willReturn(george); // given(this.owners.findById(TEST_OWNER_ID)).willReturn(george);
} // }
//
@Test // @Test
public void testInitCreationForm() throws Exception { // public void testInitCreationForm() throws Exception {
mockMvc.perform(get("/owners/new")) // mockMvc.perform(get("/owners/new"))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attributeExists("owner")) // .andExpect(model().attributeExists("owner"))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); // .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} // }
//
@Test // @Test
public void testProcessCreationFormSuccess() throws Exception { // public void testProcessCreationFormSuccess() throws Exception {
mockMvc.perform(post("/owners/new") // mockMvc.perform(post("/owners/new")
.param("firstName", "Joe") // .param("firstName", "Joe")
.param("lastName", "Bloggs") // .param("lastName", "Bloggs")
.param("address", "123 Caramel Street") // .param("address", "123 Caramel Street")
.param("city", "London") // .param("city", "London")
.param("telephone", "01316761638") // .param("telephone", "01316761638")
) // )
.andExpect(status().is3xxRedirection()); // .andExpect(status().is3xxRedirection());
} // }
//
@Test // @Test
public void testProcessCreationFormHasErrors() throws Exception { // public void testProcessCreationFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/new") // mockMvc.perform(post("/owners/new")
.param("firstName", "Joe") // .param("firstName", "Joe")
.param("lastName", "Bloggs") // .param("lastName", "Bloggs")
.param("city", "London") // .param("city", "London")
) // )
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attributeHasErrors("owner")) // .andExpect(model().attributeHasErrors("owner"))
.andExpect(model().attributeHasFieldErrors("owner", "address")) // .andExpect(model().attributeHasFieldErrors("owner", "address"))
.andExpect(model().attributeHasFieldErrors("owner", "telephone")) // .andExpect(model().attributeHasFieldErrors("owner", "telephone"))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); // .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} // }
//
@Test // @Test
public void testInitFindForm() throws Exception { // public void testInitFindForm() throws Exception {
mockMvc.perform(get("/owners/find")) // mockMvc.perform(get("/owners/find"))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attributeExists("owner")) // .andExpect(model().attributeExists("owner"))
.andExpect(view().name("owners/findOwners")); // .andExpect(view().name("owners/findOwners"));
} // }
//
@Test // @Test
public void testProcessFindFormSuccess() throws Exception { // public void testProcessFindFormSuccess() throws Exception {
given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner())); // given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner()));
mockMvc.perform(get("/owners")) // mockMvc.perform(get("/owners"))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(view().name("owners/ownersList")); // .andExpect(view().name("owners/ownersList"));
} // }
//
@Test // @Test
public void testProcessFindFormByLastName() throws Exception { // public void testProcessFindFormByLastName() throws Exception {
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george)); // given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
mockMvc.perform(get("/owners") // mockMvc.perform(get("/owners")
.param("lastName", "Franklin") // .param("lastName", "Franklin")
) // )
.andExpect(status().is3xxRedirection()) // .andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); // .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
} // }
//
@Test // @Test
public void testProcessFindFormNoOwnersFound() throws Exception { // public void testProcessFindFormNoOwnersFound() throws Exception {
mockMvc.perform(get("/owners") // mockMvc.perform(get("/owners")
.param("lastName", "Unknown Surname") // .param("lastName", "Unknown Surname")
) // )
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attributeHasFieldErrors("owner", "lastName")) // .andExpect(model().attributeHasFieldErrors("owner", "lastName"))
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) // .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
.andExpect(view().name("owners/findOwners")); // .andExpect(view().name("owners/findOwners"));
} // }
//
@Test // @Test
public void testInitUpdateOwnerForm() throws Exception { // public void testInitUpdateOwnerForm() throws Exception {
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)) // mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attributeExists("owner")) // .andExpect(model().attributeExists("owner"))
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) // .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
.andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) // .andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) // .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
.andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) // .andExpect(model().attribute("owner", hasProperty("city", is("Madison"))))
.andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) // .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023"))))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); // .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} // }
//
@Test // @Test
public void testProcessUpdateOwnerFormSuccess() throws Exception { // public void testProcessUpdateOwnerFormSuccess() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID) // mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
.param("firstName", "Joe") // .param("firstName", "Joe")
.param("lastName", "Bloggs") // .param("lastName", "Bloggs")
.param("address", "123 Caramel Street") // .param("address", "123 Caramel Street")
.param("city", "London") // .param("city", "London")
.param("telephone", "01616291589") // .param("telephone", "01616291589")
) // )
.andExpect(status().is3xxRedirection()) // .andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); // .andExpect(view().name("redirect:/owners/{ownerId}"));
} // }
//
@Test // @Test
public void testProcessUpdateOwnerFormHasErrors() throws Exception { // public void testProcessUpdateOwnerFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID) // mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
.param("firstName", "Joe") // .param("firstName", "Joe")
.param("lastName", "Bloggs") // .param("lastName", "Bloggs")
.param("city", "London") // .param("city", "London")
) // )
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attributeHasErrors("owner")) // .andExpect(model().attributeHasErrors("owner"))
.andExpect(model().attributeHasFieldErrors("owner", "address")) // .andExpect(model().attributeHasFieldErrors("owner", "address"))
.andExpect(model().attributeHasFieldErrors("owner", "telephone")) // .andExpect(model().attributeHasFieldErrors("owner", "telephone"))
.andExpect(view().name("owners/createOrUpdateOwnerForm")); // .andExpect(view().name("owners/createOrUpdateOwnerForm"));
} // }
//
@Test // @Test
public void testShowOwner() throws Exception { // public void testShowOwner() throws Exception {
mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)) // mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) // .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
.andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) // .andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) // .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
.andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) // .andExpect(model().attribute("owner", hasProperty("city", is("Madison"))))
.andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) // .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023"))))
.andExpect(view().name("owners/ownerDetails")); // .andExpect(view().name("owners/ownerDetails"));
} // }
//
} //}

View file

@ -1,145 +1,145 @@
/* ///*
* Copyright 2012-2019 the original author or authors. // * Copyright 2012-2019 the original author or authors.
* // *
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* // *
* https://www.apache.org/licenses/LICENSE-2.0 // * https://www.apache.org/licenses/LICENSE-2.0
* // *
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
//
package org.springframework.samples.petclinic.owner; //package org.springframework.samples.petclinic.owner;
//
import static org.mockito.BDDMockito.given; //import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; //import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; //import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
//
import org.assertj.core.util.Lists; //import org.assertj.core.util.Lists;
import org.junit.Before; //import org.junit.Before;
import org.junit.Test; //import org.junit.Test;
import org.junit.runner.RunWith; //import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; //import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; //import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan; //import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType; //import org.springframework.context.annotation.FilterType;
import org.springframework.samples.petclinic.owner.Owner; //import org.springframework.samples.petclinic.owner.Owner;
import org.springframework.samples.petclinic.owner.OwnerRepository; //import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.samples.petclinic.owner.Pet; //import org.springframework.samples.petclinic.owner.Pet;
import org.springframework.samples.petclinic.owner.PetController; //import org.springframework.samples.petclinic.owner.PetController;
import org.springframework.samples.petclinic.owner.PetRepository; //import org.springframework.samples.petclinic.owner.PetRepository;
import org.springframework.samples.petclinic.owner.PetType; //import org.springframework.samples.petclinic.owner.PetType;
import org.springframework.samples.petclinic.owner.PetTypeFormatter; //import org.springframework.samples.petclinic.owner.PetTypeFormatter;
import org.springframework.test.context.junit4.SpringRunner; //import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; //import org.springframework.test.web.servlet.MockMvc;
//
/** ///**
* Test class for the {@link PetController} // * Test class for the {@link PetController}
* // *
* @author Colin But // * @author Colin But
*/ // */
@RunWith(SpringRunner.class) //@RunWith(SpringRunner.class)
@WebMvcTest(value = PetController.class, //@WebMvcTest(value = PetController.class,
includeFilters = @ComponentScan.Filter( // includeFilters = @ComponentScan.Filter(
value = PetTypeFormatter.class, // value = PetTypeFormatter.class,
type = FilterType.ASSIGNABLE_TYPE)) // type = FilterType.ASSIGNABLE_TYPE))
public class PetControllerTests { //public class PetControllerTests {
//
private static final int TEST_OWNER_ID = 1; // private static final int TEST_OWNER_ID = 1;
private static final int TEST_PET_ID = 1; // private static final int TEST_PET_ID = 1;
//
//
@Autowired // @Autowired
private MockMvc mockMvc; // private MockMvc mockMvc;
//
@MockBean // @MockBean
private PetRepository pets; // private PetRepository pets;
//
@MockBean // @MockBean
private OwnerRepository owners; // private OwnerRepository owners;
//
@Before // @Before
public void setup() { // public void setup() {
PetType cat = new PetType(); // PetType cat = new PetType();
cat.setId(3); // cat.setId(3);
cat.setName("hamster"); // cat.setName("hamster");
given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat)); // given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat));
given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner()); // given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner());
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); // given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
//
} // }
//
@Test // @Test
public void testInitCreationForm() throws Exception { // public void testInitCreationForm() throws Exception {
mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)) // mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdatePetForm")) // .andExpect(view().name("pets/createOrUpdatePetForm"))
.andExpect(model().attributeExists("pet")); // .andExpect(model().attributeExists("pet"));
} // }
//
@Test // @Test
public void testProcessCreationFormSuccess() throws Exception { // public void testProcessCreationFormSuccess() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID) // mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
.param("name", "Betty") // .param("name", "Betty")
.param("type", "hamster") // .param("type", "hamster")
.param("birthDate", "2015-02-12") // .param("birthDate", "2015-02-12")
) // )
.andExpect(status().is3xxRedirection()) // .andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); // .andExpect(view().name("redirect:/owners/{ownerId}"));
} // }
//
@Test // @Test
public void testProcessCreationFormHasErrors() throws Exception { // public void testProcessCreationFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID) // mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
.param("name", "Betty") // .param("name", "Betty")
.param("birthDate", "2015-02-12") // .param("birthDate", "2015-02-12")
) // )
.andExpect(model().attributeHasNoErrors("owner")) // .andExpect(model().attributeHasNoErrors("owner"))
.andExpect(model().attributeHasErrors("pet")) // .andExpect(model().attributeHasErrors("pet"))
.andExpect(model().attributeHasFieldErrors("pet", "type")) // .andExpect(model().attributeHasFieldErrors("pet", "type"))
.andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")) // .andExpect(model().attributeHasFieldErrorCode("pet", "type", "required"))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdatePetForm")); // .andExpect(view().name("pets/createOrUpdatePetForm"));
} // }
//
@Test // @Test
public void testInitUpdateForm() throws Exception { // public void testInitUpdateForm() throws Exception {
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)) // mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(model().attributeExists("pet")) // .andExpect(model().attributeExists("pet"))
.andExpect(view().name("pets/createOrUpdatePetForm")); // .andExpect(view().name("pets/createOrUpdatePetForm"));
} // }
//
@Test // @Test
public void testProcessUpdateFormSuccess() throws Exception { // public void testProcessUpdateFormSuccess() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID) // mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
.param("name", "Betty") // .param("name", "Betty")
.param("type", "hamster") // .param("type", "hamster")
.param("birthDate", "2015-02-12") // .param("birthDate", "2015-02-12")
) // )
.andExpect(status().is3xxRedirection()) // .andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); // .andExpect(view().name("redirect:/owners/{ownerId}"));
} // }
//
@Test // @Test
public void testProcessUpdateFormHasErrors() throws Exception { // public void testProcessUpdateFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID) // mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
.param("name", "Betty") // .param("name", "Betty")
.param("birthDate", "2015/02/12") // .param("birthDate", "2015/02/12")
) // )
.andExpect(model().attributeHasNoErrors("owner")) // .andExpect(model().attributeHasNoErrors("owner"))
.andExpect(model().attributeHasErrors("pet")) // .andExpect(model().attributeHasErrors("pet"))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdatePetForm")); // .andExpect(view().name("pets/createOrUpdatePetForm"));
} // }
//
} //}

View file

@ -1,93 +1,93 @@
/* ///*
* Copyright 2012-2019 the original author or authors. // * Copyright 2012-2019 the original author or authors.
* // *
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* // *
* https://www.apache.org/licenses/LICENSE-2.0 // * https://www.apache.org/licenses/LICENSE-2.0
* // *
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
//
package org.springframework.samples.petclinic.owner; //package org.springframework.samples.petclinic.owner;
//
import java.text.ParseException; //import java.text.ParseException;
import java.util.ArrayList; //import java.util.ArrayList;
import java.util.Collection; //import java.util.Collection;
import java.util.List; //import java.util.List;
import java.util.Locale; //import java.util.Locale;
//
import org.junit.Before; //import org.junit.Before;
import org.junit.Test; //import org.junit.Test;
import org.junit.runner.RunWith; //import org.junit.runner.RunWith;
import org.mockito.Mock; //import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; //import org.mockito.junit.MockitoJUnitRunner;
//
import static org.assertj.core.api.Assertions.assertThat; //import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given; //import static org.mockito.BDDMockito.given;
//
/** ///**
* Test class for {@link PetTypeFormatter} // * Test class for {@link PetTypeFormatter}
* // *
* @author Colin But // * @author Colin But
*/ // */
@RunWith(MockitoJUnitRunner.class) //@RunWith(MockitoJUnitRunner.class)
public class PetTypeFormatterTests { //public class PetTypeFormatterTests {
//
@Mock // @Mock
private PetRepository pets; // private PetRepository pets;
//
private PetTypeFormatter petTypeFormatter; // private PetTypeFormatter petTypeFormatter;
//
@Before // @Before
public void setup() { // public void setup() {
this.petTypeFormatter = new PetTypeFormatter(pets); // this.petTypeFormatter = new PetTypeFormatter(pets);
} // }
//
@Test // @Test
public void testPrint() { // public void testPrint() {
PetType petType = new PetType(); // PetType petType = new PetType();
petType.setName("Hamster"); // petType.setName("Hamster");
String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH); // String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH);
assertThat(petTypeName).isEqualTo("Hamster"); // assertThat(petTypeName).isEqualTo("Hamster");
} // }
//
@Test // @Test
public void shouldParse() throws ParseException { // public void shouldParse() throws ParseException {
given(this.pets.findPetTypes()).willReturn(makePetTypes()); // given(this.pets.findPetTypes()).willReturn(makePetTypes());
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); // PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
assertThat(petType.getName()).isEqualTo("Bird"); // assertThat(petType.getName()).isEqualTo("Bird");
} // }
//
@Test(expected = ParseException.class) // @Test(expected = ParseException.class)
public void shouldThrowParseException() throws ParseException { // public void shouldThrowParseException() throws ParseException {
given(this.pets.findPetTypes()).willReturn(makePetTypes()); // given(this.pets.findPetTypes()).willReturn(makePetTypes());
petTypeFormatter.parse("Fish", Locale.ENGLISH); // petTypeFormatter.parse("Fish", Locale.ENGLISH);
} // }
//
/** // /**
* Helper method to produce some sample pet types just for test purpose // * Helper method to produce some sample pet types just for test purpose
* // *
* @return {@link Collection} of {@link PetType} // * @return {@link Collection} of {@link PetType}
*/ // */
private List<PetType> makePetTypes() { // private List<PetType> makePetTypes() {
List<PetType> petTypes = new ArrayList<>(); // List<PetType> petTypes = new ArrayList<>();
petTypes.add(new PetType() { // petTypes.add(new PetType() {
{ // {
setName("Dog"); // setName("Dog");
} // }
}); // });
petTypes.add(new PetType() { // petTypes.add(new PetType() {
{ // {
setName("Bird"); // setName("Bird");
} // }
}); // });
return petTypes; // return petTypes;
} // }
//
} //}

View file

@ -1,91 +1,91 @@
/* ///*
* Copyright 2012-2019 the original author or authors. // * Copyright 2012-2019 the original author or authors.
* // *
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* // *
* https://www.apache.org/licenses/LICENSE-2.0 // * https://www.apache.org/licenses/LICENSE-2.0
* // *
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
//
package org.springframework.samples.petclinic.owner; //package org.springframework.samples.petclinic.owner;
//
import static org.mockito.BDDMockito.given; //import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; //import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; //import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; //import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
//
import org.junit.Before; //import org.junit.Before;
import org.junit.Test; //import org.junit.Test;
import org.junit.runner.RunWith; //import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; //import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; //import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.samples.petclinic.owner.Pet; //import org.springframework.samples.petclinic.owner.Pet;
import org.springframework.samples.petclinic.owner.PetRepository; //import org.springframework.samples.petclinic.owner.PetRepository;
import org.springframework.samples.petclinic.owner.VisitController; //import org.springframework.samples.petclinic.owner.VisitController;
import org.springframework.samples.petclinic.visit.VisitRepository; //import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.test.context.junit4.SpringRunner; //import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; //import org.springframework.test.web.servlet.MockMvc;
//
/** ///**
* Test class for {@link VisitController} // * Test class for {@link VisitController}
* // *
* @author Colin But // * @author Colin But
*/ // */
@RunWith(SpringRunner.class) //@RunWith(SpringRunner.class)
@WebMvcTest(VisitController.class) //@WebMvcTest(VisitController.class)
public class VisitControllerTests { //public class VisitControllerTests {
//
private static final int TEST_PET_ID = 1; // private static final int TEST_PET_ID = 1;
//
@Autowired // @Autowired
private MockMvc mockMvc; // private MockMvc mockMvc;
//
@MockBean // @MockBean
private VisitRepository visits; // private VisitRepository visits;
//
@MockBean // @MockBean
private PetRepository pets; // private PetRepository pets;
//
@Before // @Before
public void init() { // public void init() {
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); // given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
} // }
//
@Test // @Test
public void testInitNewVisitForm() throws Exception { // public void testInitNewVisitForm() throws Exception {
mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)) // mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdateVisitForm")); // .andExpect(view().name("pets/createOrUpdateVisitForm"));
} // }
//
@Test // @Test
public void testProcessNewVisitFormSuccess() throws Exception { // public void testProcessNewVisitFormSuccess() throws Exception {
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID) // mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
.param("name", "George") // .param("name", "George")
.param("description", "Visit Description") // .param("description", "Visit Description")
) // )
.andExpect(status().is3xxRedirection()) // .andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}")); // .andExpect(view().name("redirect:/owners/{ownerId}"));
} // }
//
@Test // @Test
public void testProcessNewVisitFormHasErrors() throws Exception { // public void testProcessNewVisitFormHasErrors() throws Exception {
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID) // mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
.param("name", "George") // .param("name", "George")
) // )
.andExpect(model().attributeHasErrors("visit")) // .andExpect(model().attributeHasErrors("visit"))
.andExpect(status().isOk()) // .andExpect(status().isOk())
.andExpect(view().name("pets/createOrUpdateVisitForm")); // .andExpect(view().name("pets/createOrUpdateVisitForm"));
} // }
//
} //}

View file

@ -1,222 +1,222 @@
/* ///*
* Copyright 2012-2019 the original author or authors. // * Copyright 2012-2019 the original author or authors.
* // *
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* // *
* https://www.apache.org/licenses/LICENSE-2.0 // * https://www.apache.org/licenses/LICENSE-2.0
* // *
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
//
package org.springframework.samples.petclinic.service; //package org.springframework.samples.petclinic.service;
//
import static org.assertj.core.api.Assertions.assertThat; //import static org.assertj.core.api.Assertions.assertThat;
//
import java.time.LocalDate; //import java.time.LocalDate;
import java.util.Collection; //import java.util.Collection;
//
import org.junit.Test; //import org.junit.Test;
import org.junit.runner.RunWith; //import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; //import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.ComponentScan; //import org.springframework.context.annotation.ComponentScan;
import org.springframework.samples.petclinic.owner.Owner; //import org.springframework.samples.petclinic.owner.Owner;
import org.springframework.samples.petclinic.owner.OwnerRepository; //import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.samples.petclinic.owner.Pet; //import org.springframework.samples.petclinic.owner.Pet;
import org.springframework.samples.petclinic.owner.PetRepository; //import org.springframework.samples.petclinic.owner.PetRepository;
import org.springframework.samples.petclinic.owner.PetType; //import org.springframework.samples.petclinic.owner.PetType;
import org.springframework.samples.petclinic.vet.Vet; //import org.springframework.samples.petclinic.vet.Vet;
import org.springframework.samples.petclinic.vet.VetRepository; //import org.springframework.samples.petclinic.vet.VetRepository;
import org.springframework.samples.petclinic.visit.Visit; //import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository; //import org.springframework.samples.petclinic.visit.VisitRepository;
import org.springframework.stereotype.Service; //import org.springframework.stereotype.Service;
import org.springframework.test.context.junit4.SpringRunner; //import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional; //import org.springframework.transaction.annotation.Transactional;
//
/** ///**
* Integration test of the Service and the Repository layer. // * Integration test of the Service and the Repository layer.
* <p> // * <p>
* ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided by the Spring // * ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided by the Spring
* TestContext Framework: </p> <ul> <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up // * TestContext Framework: </p> <ul> <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up
* time between test execution.</li> <li><strong>Dependency Injection</strong> of test fixture instances, meaning that // * time between test execution.</li> <li><strong>Dependency Injection</strong> of test fixture instances, meaning that
* we don't need to perform application context lookups. See the use of {@link Autowired @Autowired} on the <code>{@link // * we don't need to perform application context lookups. See the use of {@link Autowired @Autowired} on the <code>{@link
* ClinicServiceTests#clinicService clinicService}</code> instance variable, which uses autowiring <em>by // * ClinicServiceTests#clinicService clinicService}</code> instance variable, which uses autowiring <em>by
* type</em>. <li><strong>Transaction management</strong>, meaning each test method is executed in its own transaction, // * type</em>. <li><strong>Transaction management</strong>, meaning each test method is executed in its own transaction,
* which is automatically rolled back by default. Thus, even if tests insert or otherwise change database state, there // * which is automatically rolled back by default. Thus, even if tests insert or otherwise change database state, there
* is no need for a teardown or cleanup script. <li> An {@link org.springframework.context.ApplicationContext // * is no need for a teardown or cleanup script. <li> An {@link org.springframework.context.ApplicationContext
* ApplicationContext} is also inherited and can be used for explicit bean lookup if necessary. </li> </ul> // * ApplicationContext} is also inherited and can be used for explicit bean lookup if necessary. </li> </ul>
* // *
* @author Ken Krebs // * @author Ken Krebs
* @author Rod Johnson // * @author Rod Johnson
* @author Juergen Hoeller // * @author Juergen Hoeller
* @author Sam Brannen // * @author Sam Brannen
* @author Michael Isvy // * @author Michael Isvy
* @author Dave Syer // * @author Dave Syer
*/ // */
//
@RunWith(SpringRunner.class) //@RunWith(SpringRunner.class)
@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class)) //@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class))
public class ClinicServiceTests { //public class ClinicServiceTests {
//
@Autowired // @Autowired
protected OwnerRepository owners; // protected OwnerRepository owners;
//
@Autowired // @Autowired
protected PetRepository pets; // protected PetRepository pets;
//
@Autowired // @Autowired
protected VisitRepository visits; // protected VisitRepository visits;
//
@Autowired // @Autowired
protected VetRepository vets; // protected VetRepository vets;
//
@Test // @Test
public void shouldFindOwnersByLastName() { // public void shouldFindOwnersByLastName() {
Collection<Owner> owners = this.owners.findByLastName("Davis"); // Collection<Owner> owners = this.owners.findByLastName("Davis");
assertThat(owners).hasSize(2); // assertThat(owners).hasSize(2);
//
owners = this.owners.findByLastName("Daviss"); // owners = this.owners.findByLastName("Daviss");
assertThat(owners).isEmpty(); // assertThat(owners).isEmpty();
} // }
//
@Test // @Test
public void shouldFindSingleOwnerWithPet() { // public void shouldFindSingleOwnerWithPet() {
Owner owner = this.owners.findById(1); // Owner owner = this.owners.findById(1);
assertThat(owner.getLastName()).startsWith("Franklin"); // assertThat(owner.getLastName()).startsWith("Franklin");
assertThat(owner.getPets()).hasSize(1); // assertThat(owner.getPets()).hasSize(1);
assertThat(owner.getPets().get(0).getType()).isNotNull(); // assertThat(owner.getPets().get(0).getType()).isNotNull();
assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat"); // assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat");
} // }
//
@Test // @Test
@Transactional // @Transactional
public void shouldInsertOwner() { // public void shouldInsertOwner() {
Collection<Owner> owners = this.owners.findByLastName("Schultz"); // Collection<Owner> owners = this.owners.findByLastName("Schultz");
int found = owners.size(); // int found = owners.size();
//
Owner owner = new Owner(); // Owner owner = new Owner();
owner.setFirstName("Sam"); // owner.setFirstName("Sam");
owner.setLastName("Schultz"); // owner.setLastName("Schultz");
owner.setAddress("4, Evans Street"); // owner.setAddress("4, Evans Street");
owner.setCity("Wollongong"); // owner.setCity("Wollongong");
owner.setTelephone("4444444444"); // owner.setTelephone("4444444444");
this.owners.save(owner); // this.owners.save(owner);
assertThat(owner.getId().longValue()).isNotEqualTo(0); // assertThat(owner.getId().longValue()).isNotEqualTo(0);
//
owners = this.owners.findByLastName("Schultz"); // owners = this.owners.findByLastName("Schultz");
assertThat(owners.size()).isEqualTo(found + 1); // assertThat(owners.size()).isEqualTo(found + 1);
} // }
//
@Test // @Test
@Transactional // @Transactional
public void shouldUpdateOwner() { // public void shouldUpdateOwner() {
Owner owner = this.owners.findById(1); // Owner owner = this.owners.findById(1);
String oldLastName = owner.getLastName(); // String oldLastName = owner.getLastName();
String newLastName = oldLastName + "X"; // String newLastName = oldLastName + "X";
//
owner.setLastName(newLastName); // owner.setLastName(newLastName);
this.owners.save(owner); // this.owners.save(owner);
//
// retrieving new name from database // // retrieving new name from database
owner = this.owners.findById(1); // owner = this.owners.findById(1);
assertThat(owner.getLastName()).isEqualTo(newLastName); // assertThat(owner.getLastName()).isEqualTo(newLastName);
} // }
//
@Test // @Test
public void shouldFindPetWithCorrectId() { // public void shouldFindPetWithCorrectId() {
Pet pet7 = this.pets.findById(7); // Pet pet7 = this.pets.findById(7);
assertThat(pet7.getName()).startsWith("Samantha"); // assertThat(pet7.getName()).startsWith("Samantha");
assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean"); // assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
//
} // }
//
@Test // @Test
public void shouldFindAllPetTypes() { // public void shouldFindAllPetTypes() {
Collection<PetType> petTypes = this.pets.findPetTypes(); // Collection<PetType> petTypes = this.pets.findPetTypes();
//
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1); // PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
assertThat(petType1.getName()).isEqualTo("cat"); // assertThat(petType1.getName()).isEqualTo("cat");
PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4); // PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
assertThat(petType4.getName()).isEqualTo("snake"); // assertThat(petType4.getName()).isEqualTo("snake");
} // }
//
@Test // @Test
@Transactional // @Transactional
public void shouldInsertPetIntoDatabaseAndGenerateId() { // public void shouldInsertPetIntoDatabaseAndGenerateId() {
Owner owner6 = this.owners.findById(6); // Owner owner6 = this.owners.findById(6);
int found = owner6.getPets().size(); // int found = owner6.getPets().size();
//
Pet pet = new Pet(); // Pet pet = new Pet();
pet.setName("bowser"); // pet.setName("bowser");
Collection<PetType> types = this.pets.findPetTypes(); // Collection<PetType> types = this.pets.findPetTypes();
pet.setType(EntityUtils.getById(types, PetType.class, 2)); // pet.setType(EntityUtils.getById(types, PetType.class, 2));
pet.setBirthDate(LocalDate.now()); // pet.setBirthDate(LocalDate.now());
owner6.addPet(pet); // owner6.addPet(pet);
assertThat(owner6.getPets().size()).isEqualTo(found + 1); // assertThat(owner6.getPets().size()).isEqualTo(found + 1);
//
this.pets.save(pet); // this.pets.save(pet);
this.owners.save(owner6); // this.owners.save(owner6);
//
owner6 = this.owners.findById(6); // owner6 = this.owners.findById(6);
assertThat(owner6.getPets().size()).isEqualTo(found + 1); // assertThat(owner6.getPets().size()).isEqualTo(found + 1);
// checks that id has been generated // // checks that id has been generated
assertThat(pet.getId()).isNotNull(); // assertThat(pet.getId()).isNotNull();
} // }
//
@Test // @Test
@Transactional // @Transactional
public void shouldUpdatePetName() throws Exception { // public void shouldUpdatePetName() throws Exception {
Pet pet7 = this.pets.findById(7); // Pet pet7 = this.pets.findById(7);
String oldName = pet7.getName(); // String oldName = pet7.getName();
//
String newName = oldName + "X"; // String newName = oldName + "X";
pet7.setName(newName); // pet7.setName(newName);
this.pets.save(pet7); // this.pets.save(pet7);
//
pet7 = this.pets.findById(7); // pet7 = this.pets.findById(7);
assertThat(pet7.getName()).isEqualTo(newName); // assertThat(pet7.getName()).isEqualTo(newName);
} // }
//
@Test // @Test
public void shouldFindVets() { // public void shouldFindVets() {
Collection<Vet> vets = this.vets.findAll(); // Collection<Vet> vets = this.vets.findAll();
//
Vet vet = EntityUtils.getById(vets, Vet.class, 3); // Vet vet = EntityUtils.getById(vets, Vet.class, 3);
assertThat(vet.getLastName()).isEqualTo("Douglas"); // assertThat(vet.getLastName()).isEqualTo("Douglas");
assertThat(vet.getNrOfSpecialties()).isEqualTo(2); // assertThat(vet.getNrOfSpecialties()).isEqualTo(2);
assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry"); // assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry");
assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery"); // assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery");
} // }
//
@Test // @Test
@Transactional // @Transactional
public void shouldAddNewVisitForPet() { // public void shouldAddNewVisitForPet() {
Pet pet7 = this.pets.findById(7); // Pet pet7 = this.pets.findById(7);
int found = pet7.getVisits().size(); // int found = pet7.getVisits().size();
Visit visit = new Visit(); // Visit visit = new Visit();
pet7.addVisit(visit); // pet7.addVisit(visit);
visit.setDescription("test"); // visit.setDescription("test");
this.visits.save(visit); // this.visits.save(visit);
this.pets.save(pet7); // this.pets.save(pet7);
//
pet7 = this.pets.findById(7); // pet7 = this.pets.findById(7);
assertThat(pet7.getVisits().size()).isEqualTo(found + 1); // assertThat(pet7.getVisits().size()).isEqualTo(found + 1);
assertThat(visit.getId()).isNotNull(); // assertThat(visit.getId()).isNotNull();
} // }
//
@Test // @Test
public void shouldFindVisitsByPetId() throws Exception { // public void shouldFindVisitsByPetId() throws Exception {
Collection<Visit> visits = this.visits.findByPetId(7); // Collection<Visit> visits = this.visits.findByPetId(7);
assertThat(visits).hasSize(2); // assertThat(visits).hasSize(2);
Visit[] visitArr = visits.toArray(new Visit[visits.size()]); // Visit[] visitArr = visits.toArray(new Visit[visits.size()]);
assertThat(visitArr[0].getDate()).isNotNull(); // assertThat(visitArr[0].getDate()).isNotNull();
assertThat(visitArr[0].getPetId()).isEqualTo(7); // assertThat(visitArr[0].getPetId()).isEqualTo(7);
} // }
//
} //}