diff --git a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeDraftsControllerIntegrationTests.java b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeDraftsControllerIntegrationTests.java index 2485b5d..6e70111 100644 --- a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeDraftsControllerIntegrationTests.java +++ b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeDraftsControllerIntegrationTests.java @@ -9,6 +9,7 @@ import app.mealsmadeeasy.api.recipe.body.RecipeDraftUpdateBody; import app.mealsmadeeasy.api.user.User; import app.mealsmadeeasy.api.user.UserCreateException; import app.mealsmadeeasy.api.user.UserService; +import app.mealsmadeeasy.api.util.NoSuchEntityWithIdException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -26,6 +27,7 @@ import java.util.UUID; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertThrows; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -82,11 +84,10 @@ public class RecipeDraftsControllerIntegrationTests { } @Test - public void whenNoUser_getReturnsUnauthorized() throws Exception { + public void whenNoDraftAndNoPrincipal_getReturnsUnauthorized() throws Exception { this.mockMvc.perform( get("/recipe-drafts/{fakeId}", UUID.randomUUID().toString()) - ) - .andExpect(status().isUnauthorized()); + ).andExpect(status().isUnauthorized()); } @Test @@ -111,6 +112,26 @@ public class RecipeDraftsControllerIntegrationTests { .andExpect(jsonPath("$.mainImage", is(nullValue()))); } + @Test + public void whenDraftExistsButNoPrincipal_returnsUnauthorized() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + this.mockMvc.perform( + get("/recipe-drafts/{id}", recipeDraft.getId()) + ).andExpect(status().isUnauthorized()); + } + + @Test + public void whenDraftExistsButWrongPrincipal_returnsForbidden() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + final User wrongViewer = this.seedUser(); + this.mockMvc.perform( + get("/recipe-drafts/{id}", recipeDraft.getId()) + .header("Authorization", "Bearer " + this.getAccessToken(wrongViewer)) + ).andExpect(status().isForbidden()); + } + @Test public void whenDraftsExist_returnDrafts() throws Exception { final User owner = this.seedUser(); @@ -125,6 +146,21 @@ public class RecipeDraftsControllerIntegrationTests { .andExpect(jsonPath("$", hasSize(2))); } + @Test + public void whenDraftsExistButWrongPrincipal_returnsNoDrafts() throws Exception { + final User owner = this.seedUser(); + this.recipeService.createDraft(owner); // seed 1 + this.recipeService.createDraft(owner); // seed 2 + final User wrongViewer = this.seedUser(); + this.mockMvc.perform( + get("/recipe-drafts") + .header("Authorization", "Bearer " + this.getAccessToken(wrongViewer)) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$", hasSize(0))); + } + @Test public void manualDraft_returnsDraft() throws Exception { final User owner = this.seedUser(); @@ -165,16 +201,14 @@ public class RecipeDraftsControllerIntegrationTests { .andExpect(status().isCreated()) .andExpect(jsonPath("$.created", is(notNullValue()))) .andExpect(jsonPath("$.state", is(RecipeDraft.State.INFER.toString()))) - .andExpect(jsonPath("$.owner.id", is(owner.getId()))); + .andExpect(jsonPath("$.owner.id", is(owner.getId()))) + .andExpect(jsonPath("$.owner.username", is(owner.getUsername()))); } } - @Test - public void whenUpdate_returnsUpdated() throws Exception { - final User owner = this.seedUser(); - final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); - final RecipeDraftUpdateBody updateBody = RecipeDraftUpdateBody.builder() + private static RecipeDraftUpdateBody getTestRecipeDraftUpdateBody() { + return RecipeDraftUpdateBody.builder() .title("Test Title") .slug("test-slug") .preparationTime(15) @@ -189,6 +223,13 @@ public class RecipeDraftsControllerIntegrationTests { .build() )) .build(); + } + + @Test + public void whenUpdate_returnsUpdated() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + final RecipeDraftUpdateBody updateBody = getTestRecipeDraftUpdateBody(); this.mockMvc.perform( put("/recipe-drafts/{id}", recipeDraft.getId()) .header("Authorization", "Bearer " + this.getAccessToken(owner)) @@ -208,4 +249,102 @@ public class RecipeDraftsControllerIntegrationTests { .andExpect(jsonPath("$.ingredients[0].notes", is("Separated"))); } + @Test + public void whenUpdateNoPrincipal_returnsUnauthorized() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + final RecipeDraftUpdateBody updateBody = getTestRecipeDraftUpdateBody(); + this.mockMvc.perform( + put("/recipe-drafts/{id}", recipeDraft.getId()) + .header("Content-Type", "application/json") + .content(this.objectMapper.writeValueAsString(updateBody)) + ).andExpect(status().isUnauthorized()); + } + + @Test + public void whenWrongPrincipalUpdate_returnsForbidden() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + final RecipeDraftUpdateBody updateBody = getTestRecipeDraftUpdateBody(); + final User wrongModifier = this.seedUser(); + this.mockMvc.perform( + put("/recipe-drafts/{id}", recipeDraft.getId()) + .header("Authorization", "Bearer " + this.getAccessToken(wrongModifier)) + .header("Content-Type", "application/json") + .content(this.objectMapper.writeValueAsString(updateBody)) + ).andExpect(status().isForbidden()); + } + + @Test + public void whenDelete_draftIsDeleted() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + this.mockMvc.perform( + delete("/recipe-drafts/{id}", recipeDraft.getId()) + .header("Authorization", "Bearer " + this.getAccessToken(owner)) + ) + .andExpect(status().isNoContent()); + assertThrows(NoSuchEntityWithIdException.class, () -> this.recipeService.getDraftById(recipeDraft.getId())); + } + + @Test + public void whenDeleteWithNoPrincipal_returnsUnauthorized() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + this.mockMvc.perform( + delete("/recipe-drafts/{id}", recipeDraft.getId()) + ).andExpect(status().isUnauthorized()); + } + + @Test + public void whenPublish_expectDraftDeletedAndRecipeCreated() throws Exception { + final User owner = this.seedUser(); + final RecipeDraft recipeDraft = this.recipeService.createDraft(owner); + recipeDraft.setTitle("Test Title"); + recipeDraft.setSlug("test-slug"); + recipeDraft.setRawText("# Hello, World!"); + this.recipeService.saveDraft(recipeDraft); + this.mockMvc.perform( + post("/recipe-drafts/{id}/publish", recipeDraft.getId()) + .header("Authorization", "Bearer " + this.getAccessToken(owner)) + ) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id", is(notNullValue()))) + .andExpect(jsonPath("$.created", is(notNullValue()))) + .andExpect(jsonPath("$.modified", is(nullValue()))) + .andExpect(jsonPath("$.title", is("Test Title"))) + .andExpect(jsonPath("$.slug", is("test-slug"))) + .andExpect(jsonPath("$.preparationTime", is(nullValue()))) + .andExpect(jsonPath("$.cookingTime", is(nullValue()))) + .andExpect(jsonPath("$.totalTime", is(nullValue()))) + .andExpect(jsonPath("$.text", is("