Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
base initial integration tests (#218)
* Initial Integration test setup, need to persist service gen entities * Now using jsonunit * Basic CRUD tests for GroupController * Cleanup * More complete delete test and todos for future tests * New Google formatter in acton * WIP Contribution guidelines * Too soon
- Loading branch information
Showing
3 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Contributing | ||
|
||
When contributing to this repository, please first discuss the change you wish to make via issue, | ||
email, or any other method with the owners of this repository before making a change. | ||
|
||
Please note we have a code of conduct, please follow it in all your interactions with the project. | ||
|
||
## Code Standards | ||
|
||
#### General | ||
1. Do not use field injection (ie. `@Value`, `@Autowired`) | ||
- Instead use an `@Autowired` or `@Value` annotated constructor | ||
- This helps to improves testability | ||
- Helps to decouple from Spring | ||
- If your constructor is feeling messy or too big - you are probably overloading the class you are working on | ||
2. If a class is dependent on more than 3 constructor arguments, a _single_ config class should encapsulate those arguments while | ||
implementing a builder pattern (ie. Lombok `@Builder` annotation) | ||
3. Do not use any implementation specific JPA code (ie. Hibernate-only annotations) | ||
- Exception for when no alternative functionality exists (ie. Postgres JSON field search) | ||
4. All of our code is auto-formatted to Google Java Format using the [fmt-maven-plugin](https://mvnrepository.com/artifact/com.coveo/fmt-maven-plugin) on build: | ||
```xml | ||
<plugin> | ||
<groupId>com.coveo</groupId> | ||
<artifactId>fmt-maven-plugin</artifactId> | ||
<version>${FMT_MVN_PLG.VERSION}</version> | ||
<executions> | ||
<execution> | ||
<goals> | ||
<goal>format</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
``` | ||
|
||
#### Service Layer | ||
1. Get * should always return Optional<T> | ||
2. Find * should always return a Collection<T> | ||
|
||
### Testing | ||
|
||
#### General | ||
1. DB via Test Containers - no in-memory DB or OS specific services | ||
2. No dependencies on any external services (ie. production micro-service) | ||
|
||
##### Unit Testing | ||
|
||
##### Integration Testing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
252 changes: 252 additions & 0 deletions
252
src/test/java/bio/overture/ego/controller/GroupControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
package bio.overture.ego.controller; | ||
|
||
import bio.overture.ego.AuthorizationServiceMain; | ||
import bio.overture.ego.model.entity.Group; | ||
import bio.overture.ego.service.GroupService; | ||
import bio.overture.ego.service.UserService; | ||
import bio.overture.ego.utils.EntityGenerator; | ||
import lombok.extern.slf4j.Slf4j; | ||
import lombok.val; | ||
import org.json.JSONException; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.web.client.TestRestTemplate; | ||
import org.springframework.boot.web.server.LocalServerPort; | ||
import org.springframework.http.*; | ||
import org.springframework.test.context.ActiveProfiles; | ||
import org.springframework.test.context.junit4.SpringRunner; | ||
|
||
import java.util.UUID; | ||
|
||
import static bio.overture.ego.utils.CollectionUtils.listOf; | ||
import static net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER; | ||
import static net.javacrumbs.jsonunit.core.Option.IGNORING_EXTRA_ARRAY_ITEMS; | ||
import static net.javacrumbs.jsonunit.fluent.JsonFluentAssert.assertThatJson; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertNotEquals; | ||
|
||
@Slf4j | ||
@ActiveProfiles("test") | ||
@RunWith(SpringRunner.class) | ||
@SpringBootTest( | ||
classes = AuthorizationServiceMain.class, | ||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | ||
public class GroupControllerTest { | ||
|
||
@LocalServerPort private int port; | ||
private TestRestTemplate restTemplate = new TestRestTemplate(); | ||
private HttpHeaders headers = new HttpHeaders(); | ||
|
||
private static boolean hasRunEntitySetup = false; | ||
|
||
@Autowired private EntityGenerator entityGenerator; | ||
@Autowired private GroupService groupService; | ||
@Autowired private UserService userService; | ||
|
||
@Before | ||
public void Setup() { | ||
|
||
// Initial setup of entities (run once | ||
if (!hasRunEntitySetup) { | ||
entityGenerator.setupTestUsers(); | ||
entityGenerator.setupTestApplications(); | ||
entityGenerator.setupTestGroups(); | ||
hasRunEntitySetup = true; | ||
} | ||
|
||
headers.add("Authorization", "Bearer TestToken"); | ||
headers.setContentType(MediaType.APPLICATION_JSON); | ||
} | ||
|
||
@Test | ||
public void AddGroup() { | ||
|
||
Group group = new Group("Wizards"); | ||
|
||
HttpEntity<Group> entity = new HttpEntity<Group>(group, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange(createURLWithPort("/groups"), HttpMethod.POST, entity, String.class); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
assertEquals(HttpStatus.OK, responseStatus); | ||
} | ||
|
||
@Test | ||
public void AddUniqueGroup() { | ||
|
||
entityGenerator.setupGroup("SameSame"); | ||
Group group = new Group("SameSame"); | ||
|
||
HttpEntity<Group> entity = new HttpEntity<Group>(group, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange(createURLWithPort("/groups"), HttpMethod.POST, entity, String.class); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
assertEquals(HttpStatus.CONFLICT, responseStatus); // TODO | ||
} | ||
|
||
@Test | ||
public void GetGroup() throws JSONException { | ||
|
||
// Groups created in setup | ||
val groupId = groupService.getByName("Group One").getId(); | ||
|
||
HttpEntity<String> entity = new HttpEntity<String>(null, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange( | ||
createURLWithPort(String.format("/groups/%s", groupId)), | ||
HttpMethod.GET, | ||
entity, | ||
String.class); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
String responseBody = response.getBody(); | ||
|
||
String expected = | ||
String.format( | ||
"{\"id\":\"%s\",\"name\":\"Group One\",\"description\":null,\"status\":null}", groupId); | ||
|
||
assertEquals(HttpStatus.OK, responseStatus); | ||
assertThatJson(responseBody).isEqualTo(expected); | ||
} | ||
|
||
@Test | ||
public void GetGroupNotFound() throws JSONException { | ||
HttpEntity<String> entity = new HttpEntity<String>(null, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange( | ||
createURLWithPort(String.format("/groups/%s", UUID.randomUUID())), | ||
HttpMethod.GET, | ||
entity, | ||
String.class); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
|
||
assertEquals(HttpStatus.NOT_FOUND, responseStatus); // TODO | ||
} | ||
|
||
@Test | ||
public void ListGroups() throws JSONException { | ||
HttpEntity<String> entity = new HttpEntity<String>(null, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange(createURLWithPort("/groups"), HttpMethod.GET, entity, String.class); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
String responseBody = response.getBody(); | ||
|
||
String expected = | ||
String.format( | ||
"[{\"id\":\"%s\",\"name\":\"Group One\",\"description\":null,\"status\":null}, {\"id\":\"%s\",\"name\":\"Group Two\",\"description\":null,\"status\":null}, {\"id\":\"%s\",\"name\":\"Group Three\",\"description\":null,\"status\":null}]", | ||
groupService.getByName("Group One").getId(), | ||
groupService.getByName("Group Two").getId(), | ||
groupService.getByName("Group Three").getId()); | ||
|
||
assertEquals(HttpStatus.OK, responseStatus); | ||
assertThatJson(responseBody) | ||
.when(IGNORING_EXTRA_ARRAY_ITEMS, IGNORING_ARRAY_ORDER) | ||
.node("resultSet") | ||
.isEqualTo(expected); | ||
} | ||
|
||
// TODO - ADD List/Filter tests | ||
|
||
@Test | ||
public void UpdateGroup() { | ||
|
||
// Groups created in setup | ||
val groupId = entityGenerator.setupGroup("Complete").getId(); | ||
|
||
Group update = new Group("Updated Complete"); | ||
update.setId(groupId); | ||
|
||
HttpEntity<Group> entity = new HttpEntity<Group>(update, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange( | ||
createURLWithPort(String.format("/groups/%s", groupId)), | ||
HttpMethod.PUT, | ||
entity, | ||
String.class); | ||
|
||
String responseBody = response.getBody(); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
assertEquals(HttpStatus.OK, responseStatus); | ||
assertThatJson(responseBody).node("id").isEqualTo(groupId); | ||
assertThatJson(responseBody).node("name").isEqualTo("Updated Complete"); | ||
} | ||
|
||
// TODO - ADD Update non-existent entity | ||
|
||
@Test | ||
public void PartialUpdateGroup() throws JSONException { | ||
|
||
// Groups created in setup | ||
val groupId = entityGenerator.setupGroup("Partial").getId(); | ||
|
||
val update = "{\"name\":\"Updated Partial\"}"; | ||
HttpEntity<String> entity = new HttpEntity<String>(update, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange( | ||
createURLWithPort(String.format("/groups/%s", groupId)), | ||
HttpMethod.PATCH, | ||
entity, | ||
String.class); // TODO - No Patch Method | ||
|
||
String responseBody = response.getBody(); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
assertEquals(HttpStatus.OK, responseStatus); | ||
assertThatJson(responseBody).node("id").isEqualTo(groupId); | ||
assertThatJson(responseBody).node("name").isEqualTo("Updated Partial"); | ||
} | ||
|
||
@Test | ||
public void DeleteOne() throws JSONException { | ||
|
||
// Groups created in setup | ||
val groupId = entityGenerator.setupGroup("Temporary").getId(); | ||
|
||
// Add a user to this group | ||
userService.addUserToGroups( | ||
userService.getByName("FirstUser@domain.com").getId().toString(), | ||
listOf(groupId.toString())); | ||
|
||
// TODO - ADD application groups relationship | ||
|
||
HttpEntity<String> entity = new HttpEntity<String>(null, headers); | ||
|
||
ResponseEntity<String> response = | ||
restTemplate.exchange( | ||
createURLWithPort(String.format("/groups/%s", groupId)), | ||
HttpMethod.DELETE, | ||
entity, | ||
String.class); | ||
|
||
HttpStatus responseStatus = response.getStatusCode(); | ||
|
||
// Check http response | ||
assertEquals(HttpStatus.OK, responseStatus); | ||
|
||
// Check user-group relationship is also deleted | ||
assertNotEquals(null, userService.getByName("FirstUser@domain.com")); | ||
|
||
// Check group is deleted | ||
assertEquals(null, groupService.getByName("Temporary")); | ||
} | ||
|
||
// TODO - ADD tests for adding user/apps to groups | ||
|
||
private String createURLWithPort(String uri) { | ||
return "http://localhost:" + port + uri; | ||
} | ||
} |