PAN-52 Finished creating the ProofController and writing all unit tests

This commit is contained in:
atusa
2019-03-15 15:58:23 -06:00
parent bd7455c679
commit 4b866017a1
7 changed files with 333 additions and 10 deletions
@@ -36,7 +36,7 @@ version int default 1
CREATE TABLE proofs CREATE TABLE proofs
( (
id INT NOT NULL AUTO_INCREMENT, id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(512) NOT NULL, theorem_name VARCHAR(512) NOT NULL,
branch VARCHAR(512) NOT NULL, branch VARCHAR(512) NOT NULL,
theorem INT NOT NULL, theorem INT NOT NULL,
FOREIGN KEY fk_theorem (theorem) REFERENCES theorems (id) ON DELETE NO ACTION ON UPDATE NO ACTION, FOREIGN KEY fk_theorem (theorem) REFERENCES theorems (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
@@ -2,13 +2,18 @@ package edu.msudenver.tsp.persistence.controller;
import edu.msudenver.tsp.persistence.dto.ProofDto; import edu.msudenver.tsp.persistence.dto.ProofDto;
import edu.msudenver.tsp.persistence.repository.ProofRepository; import edu.msudenver.tsp.persistence.repository.ProofRepository;
import edu.msudenver.tsp.utilities.PersistenceUtilities;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.util.StopWatch; import org.springframework.util.StopWatch;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.groups.Default;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -97,4 +102,140 @@ public class ProofController {
LOG.info("Returning list of proofs with branch {}", branch); LOG.info("Returning list of proofs with branch {}", branch);
return new ResponseEntity<>(listOfProofs, HttpStatus.OK); return new ResponseEntity<>(listOfProofs, HttpStatus.OK);
} }
@GetMapping("/{theorem_name}")
public @ResponseBody
ResponseEntity<List<ProofDto>> getAllProofsByTheoremName(@PathVariable("theorem_name") final String theoremName) {
LOG.info("Received request to query for proofs of the theorem {}", theoremName);
if (theoremName == null) {
LOG.error("ERROR: theorem name was null");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
LOG.debug("Querying for proofs of the theorem {}", theoremName);
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
final List<ProofDto> listOfProofs = proofRepository.findByTheoremName(theoremName);
stopWatch.stop();
LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete");
LOG.info("Returning list of all proofs with size " + listOfProofs.size());
if (listOfProofs.isEmpty()) {
LOG.warn("No proofs were found of the theorem {}", theoremName);
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
LOG.info("Returning list of proofs for the theorem {}", theoremName);
return new ResponseEntity<>(listOfProofs, HttpStatus.OK);
}
@PostMapping("/")
@Validated({ProofDto.Insert.class, Default.class})
public @ResponseBody ResponseEntity<ProofDto> insertProof(
@Valid @RequestBody final ProofDto proofDto,
final BindingResult bindingResult) {
LOG.info("Received request to insert a new proof");
if (bindingResult.hasErrors()) {
LOG.error("Binding result is unprocessable");
return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY);
}
if (proofDto == null) {
LOG.error("Passed entity is null");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
LOG.debug("Saving new proof");
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
final ProofDto savedProof = proofRepository.save(proofDto);
stopWatch.stop();
LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis());
LOG.info("Returning the newly created proof with id {}", savedProof.getId());
return new ResponseEntity<>(savedProof, HttpStatus.CREATED);
}
@PatchMapping("/{id}")
public @ResponseBody ResponseEntity<ProofDto> updateProof(
@PathVariable("id") final Integer id,
@RequestBody final ProofDto proofDto, final BindingResult bindingResult) {
LOG.info("Received request to update a proof");
if (bindingResult.hasErrors()) {
LOG.error("Binding result is unprocessable");
return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY);
}
if (proofDto == null) {
LOG.error("Passed entity is null");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
if (id == null) {
LOG.error("Proof ID must be specified");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
LOG.debug("Checking for existence of proof with id " + id);
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
final Optional<ProofDto> existingProof = proofRepository.findById(id);
stopWatch.stop();
LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis());
if (!existingProof.isPresent()) {
LOG.error("No proof associated with id {}", id);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
PersistenceUtilities.copyNonNullProperties(proofDto, existingProof.get());
existingProof.get().setVersion(existingProof.get().getVersion()+ 1);
LOG.info("Updating proof with id {}", id);
LOG.debug("Querying for proof with ID {}", id);
stopWatch.start();
final ProofDto updatedProof = proofRepository.save(existingProof.get());
stopWatch.stop();
LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis());
return new ResponseEntity<>(updatedProof, HttpStatus.OK);
}
@DeleteMapping("/{id}")
public @ResponseBody ResponseEntity<Void> deleteProofById(@PathVariable("id") final Integer id) {
LOG.info("Received request to delete proof with id {}", id);
if (id == null) {
LOG.error("Specified id is null");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
LOG.debug("Deleting proof with id {}", id);
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
proofRepository.deleteById(id);
stopWatch.stop();
LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis());
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
} }
@@ -9,9 +9,11 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.util.StopWatch; import org.springframework.util.StopWatch;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.groups.Default;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -162,6 +164,7 @@ public class TheoremController {
} }
@PostMapping("/") @PostMapping("/")
@Validated({TheoremDto.Insert.class, Default.class})
public @ResponseBody ResponseEntity<TheoremDto> insertTheorem( public @ResponseBody ResponseEntity<TheoremDto> insertTheorem(
@Valid @RequestBody final TheoremDto theoremDto, @Valid @RequestBody final TheoremDto theoremDto,
final BindingResult bindingResult) { final BindingResult bindingResult) {
@@ -195,7 +198,7 @@ public class TheoremController {
@PathVariable("id") final Integer id, @PathVariable("id") final Integer id,
@RequestBody final TheoremDto theoremDto, final BindingResult bindingResult) { @RequestBody final TheoremDto theoremDto, final BindingResult bindingResult) {
LOG.info("Received request to update an account"); LOG.info("Received request to update a theorem");
if (bindingResult.hasErrors()) { if (bindingResult.hasErrors()) {
LOG.error("Binding result is unprocessable"); LOG.error("Binding result is unprocessable");
return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY);
@@ -20,7 +20,8 @@ import java.util.List;
public class ProofDto extends BaseDto implements Serializable { public class ProofDto extends BaseDto implements Serializable {
@NotBlank(groups = Insert.class) @NotBlank(groups = Insert.class)
@Size(min = 1, max = 512, message = "The name must be at least 1 character and at most 512 characters") @Size(min = 1, max = 512, message = "The name must be at least 1 character and at most 512 characters")
private String name; @Column(name = "theorem_name")
private String theoremName;
@NotBlank(groups = Insert.class) @NotBlank(groups = Insert.class)
@Size(min = 1, max = 512, message = "The branch must be at least 1 character and at most 512 characters") @Size(min = 1, max = 512, message = "The branch must be at least 1 character and at most 512 characters")
private String branch; private String branch;
@@ -29,6 +30,15 @@ public class ProofDto extends BaseDto implements Serializable {
@Temporal(TemporalType.DATE) @Column(name = "date_created") private Date dateCreated; @Temporal(TemporalType.DATE) @Column(name = "date_created") private Date dateCreated;
@Temporal(TemporalType.DATE) @Column(name = "last_updated") private Date lastUpdated; @Temporal(TemporalType.DATE) @Column(name = "last_updated") private Date lastUpdated;
@JsonProperty("theorem_name")
public String getTheoremName() {
return theoremName;
}
@JsonProperty("theorem_name")
public void setTheoremName(final String theoremName) {
this.theoremName = theoremName;
}
@JsonProperty("referenced_definitions") @JsonProperty("referenced_definitions")
public List<String> getReferencedDefinitions() { public List<String> getReferencedDefinitions() {
@@ -20,12 +20,12 @@ import java.util.List;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class TheoremDto extends BaseDto implements Serializable { public class TheoremDto extends BaseDto implements Serializable {
@NotBlank @Size(min = 1, max = 512, message = "theorem name must be between 1 and 512 characters") private String name; @NotBlank(groups = Insert.class) @Size(min = 1, max = 512, message = "theorem name must be between 1 and 512 characters") private String name;
@NotNull @Column(name = "theorem_type") private TheoremType theoremType; @NotNull(groups = Insert.class) @Column(name = "theorem_type") private TheoremType theoremType;
@NotNull(message = "a branch of mathematics that this theorem is associated with must be specified") private String branch; @NotNull(groups = Insert.class, message = "a branch of mathematics that this theorem is associated with must be specified") private String branch;
@Type(type = "json") @Column(name = "referenced_definitions", columnDefinition = "jsonb") private List<String> referencedDefinitions; @Type(type = "json") @Column(name = "referenced_definitions", columnDefinition = "jsonb") private List<String> referencedDefinitions;
@Type(type = "json") @Column(name = "referenced_theorems", columnDefinition = "jsonb") private List<String> referencedTheorems; @Type(type = "json") @Column(name = "referenced_theorems", columnDefinition = "jsonb") private List<String> referencedTheorems;
@NotNull @Column(name = "proven_status") private boolean provenStatus; @NotNull(groups = Insert.class) @Column(name = "proven_status") private boolean provenStatus;
@JsonProperty("theorem_type") @JsonProperty("theorem_type")
public TheoremType getTheoremType() { public TheoremType getTheoremType() {
@@ -68,4 +68,7 @@ public class TheoremDto extends BaseDto implements Serializable {
} }
private static final long serialVersionUID = 1545568391140364425L; private static final long serialVersionUID = 1545568391140364425L;
public interface Insert {}
} }
@@ -9,5 +9,5 @@ public interface ProofRepository extends JpaRepository<ProofDto, Integer> {
List<ProofDto> findByBranch(String branch); List<ProofDto> findByBranch(String branch);
List<ProofDto> findByName(String name); List<ProofDto> findByTheoremName(String name);
} }
@@ -26,7 +26,7 @@ public class ProofControllerTest {
@Mock private BindingResult bindingResult; @Mock private BindingResult bindingResult;
@Test @Test
public void testGetAllTheorems() { public void testGetAllProofs() {
final ProofDto proofDto = createProof(); final ProofDto proofDto = createProof();
final List<ProofDto> listOfProofs = new ArrayList<>(); final List<ProofDto> listOfProofs = new ArrayList<>();
listOfProofs.add(proofDto); listOfProofs.add(proofDto);
@@ -84,6 +84,46 @@ public class ProofControllerTest {
assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode());
} }
@Test
public void testGetAllProofsByTheoremName() {
final ProofDto proofDto = createProof();
final List<ProofDto> listOfProofs = new ArrayList<>();
listOfProofs.add(proofDto);
listOfProofs.add(proofDto);
when(proofRepository.findByTheoremName(anyString())).thenReturn(listOfProofs);
final ResponseEntity<List<ProofDto>> responseEntity = proofController.getAllProofsByTheoremName("test");
assertNotNull(responseEntity);
assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
assertTrue(responseEntity.hasBody());
assertNotNull(responseEntity.getBody());
responseEntity.getBody().forEach(proof -> assertEquals(proofDto, proof));
}
@Test
public void testGetAllProfsByTheoremName_nullTheoremName() {
final ResponseEntity<List<ProofDto>> responseEntity = proofController.getAllProofsByTheoremName(null);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
verifyZeroInteractions(proofRepository);
}
@Test
public void testGetAllProofsByTheoremName_noProofsFound() {
when(proofRepository.findByTheoremName(anyString())).thenReturn(Collections.emptyList());
final ResponseEntity<List<ProofDto>> responseEntity = proofController.getAllProofsByTheoremName("test nonexistent branch");
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode());
}
@Test @Test
public void testGetProofById() { public void testGetProofById() {
final ProofDto proofDto = createProof(); final ProofDto proofDto = createProof();
@@ -121,6 +161,132 @@ public class ProofControllerTest {
verify(proofRepository).findById(anyInt()); verify(proofRepository).findById(anyInt());
} }
@Test
public void testInsertProof() {
final ProofDto proofDto = createProof();
when(proofRepository.save(any(ProofDto.class))).thenReturn(proofDto);
final ResponseEntity<ProofDto> responseEntity = proofController.insertProof(proofDto, bindingResult);
assertNotNull(responseEntity);
assertTrue(responseEntity.hasBody());
assertNotNull(responseEntity.getBody());
assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode());
assertEquals(proofDto, responseEntity.getBody());
verify(proofRepository).save(any(ProofDto.class));
}
@Test
public void testInsertProof_proofDtoIsNull() {
final ResponseEntity responseEntity = proofController.insertProof(null, bindingResult);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
verifyZeroInteractions(proofRepository);
}
@Test
public void testInsertProof_bindingResultHasErrors() {
final ProofDto proofDto = createProof();
when(bindingResult.hasErrors()).thenReturn(true);
final ResponseEntity responseEntity = proofController.insertProof(proofDto, bindingResult);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode());
verifyZeroInteractions(proofRepository);
}
@Test
public void testUpdateProof() {
final ProofDto existingProof = createProof();
existingProof.setId(1);
existingProof.setVersion(1);
final ProofDto proofUpdate = new ProofDto();
proofUpdate.setTheoremName("Test Update");
final ProofDto updatedProof = existingProof;
updatedProof.setTheoremName("Test Update");
when(proofRepository.findById(anyInt())).thenReturn(Optional.of(existingProof));
when(proofRepository.save(any(ProofDto.class))).thenReturn(updatedProof);
final ResponseEntity<ProofDto> responseEntity = proofController.updateProof(1, proofUpdate, bindingResult);
assertNotNull(responseEntity);
assertTrue(responseEntity.hasBody());
assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
assertEquals(updatedProof, responseEntity.getBody());
verify(proofRepository).findById(anyInt());
verify(proofRepository).save(any(ProofDto.class));
}
@Test
public void testUpdateProof_bindingResultHasErrors() {
when(bindingResult.hasErrors()).thenReturn(true);
final ResponseEntity<ProofDto> responseEntity = proofController.updateProof(1, createProof(), bindingResult);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode());
verifyZeroInteractions(proofRepository);
}
@Test
public void testUpdateProof_proofDtoIsNull() {
final ResponseEntity<ProofDto> responseEntity = proofController.updateProof(1, null, bindingResult);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
verifyZeroInteractions(proofRepository);
}
@Test
public void testUpdateProof_idIsNull() {
final ResponseEntity<ProofDto> responseEntity = proofController.updateProof(null, createProof(), bindingResult);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
verifyZeroInteractions(proofRepository);
}
@Test
public void testUpdateProof_theoremDoesNotExist() {
when(proofRepository.findById(anyInt())).thenReturn(Optional.empty());
final ResponseEntity<ProofDto> responseEntity = proofController.updateProof(1, createProof(), bindingResult);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
verify(proofRepository, times(0)).save(any(ProofDto.class));
}
@Test
public void testDeleteProofById() {
doNothing().when(proofRepository).deleteById(anyInt());
final ResponseEntity responseEntity = proofController.deleteProofById(1);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode());
verify(proofRepository).deleteById(anyInt());
}
@Test
public void testDeleteProofById_idIsNull() {
final ResponseEntity responseEntity = proofController.deleteProofById(null);
assertNotNull(responseEntity);
assertFalse(responseEntity.hasBody());
assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode());
verifyZeroInteractions(proofRepository);
}
private ProofDto createProof() { private ProofDto createProof() {
final List<String> referencedTheoremsList = new ArrayList<>(); final List<String> referencedTheoremsList = new ArrayList<>();
referencedTheoremsList.add("test theorem 1"); referencedTheoremsList.add("test theorem 1");
@@ -131,7 +297,7 @@ public class ProofControllerTest {
referencedDefinitionsList.add("test definition 2"); referencedDefinitionsList.add("test definition 2");
final ProofDto proofDto = new ProofDto(); final ProofDto proofDto = new ProofDto();
proofDto.setName("Test proof"); proofDto.setTheoremName("Test proof");
proofDto.setBranch("Test branch"); proofDto.setBranch("Test branch");
proofDto.setDateCreated(new Date()); proofDto.setDateCreated(new Date());
proofDto.setReferencedTheorems(referencedTheoremsList); proofDto.setReferencedTheorems(referencedTheoremsList);