diff --git a/src/test/java/io/codeka/gaia/modules/controller/ModuleRestControllerIT.java b/src/test/java/io/codeka/gaia/modules/controller/ModuleRestControllerIT.java new file mode 100644 index 000000000..2bb659a0d --- /dev/null +++ b/src/test/java/io/codeka/gaia/modules/controller/ModuleRestControllerIT.java @@ -0,0 +1,113 @@ +package io.codeka.gaia.modules.controller; + +import io.codeka.gaia.test.MongoContainer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import static org.hamcrest.Matchers.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Simple integration test that validates the security configuration of the TeamsRestController, and its http routes + */ +@SpringBootTest +@DirtiesContext +@Testcontainers +@AutoConfigureMockMvc +@WithMockUser(value = "admin", roles = "ADMIN") +class ModuleRestControllerIT { + + @Container + private static MongoContainer mongoContainer = new MongoContainer() + .withScript("src/test/resources/db/00_team.js") + .withScript("src/test/resources/db/10_user.js") + .withScript("src/test/resources/db/20_module.js"); + + @Autowired + private MockMvc mockMvc; + + @BeforeEach + void setup() { + mongoContainer.resetDatabase(); + } + + @Test + @WithMockUser("Mary J") + void findAllModules_shouldReturnLimitedModules_forStandardUsers() throws Exception { + mockMvc.perform(get("/api/modules")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0]name", is("terraform-docker-mongo-limited"))) + .andExpect(jsonPath("$[0]authorizedTeams..id", contains("Not Ze Team"))); + } + + @Test + void findAllModules_shouldReturnAllModules_forAdmin() throws Exception { + mockMvc.perform(get("/api/modules")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(2))) + .andExpect(jsonPath("$[*]name", contains("terraform-docker-mongo", "terraform-docker-mongo-limited"))) + .andExpect(jsonPath("$..authorizedTeams..id", contains("Ze Team", "Not Ze Team"))); + } + + @Test + @WithMockUser("Mary J") + void findModule_shouldReturnModule_forStandardUsers() throws Exception { + mockMvc.perform(get("/api/modules/845543d0-20a5-466c-8978-33c9a4661606")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name", is("terraform-docker-mongo-limited"))); + } + + @Test + @WithMockUser("Mary J") + void findModule_shouldNotReturnModuleOfOtherTeams_forStandardUsers() throws Exception { + mockMvc.perform(get("/api/modules/e01f9925-a559-45a2-8a55-f93dc434c676")) + .andExpect(status().isNotFound()); + } + + @Test + void findModule_shouldReturnModules_forAdmin() throws Exception { + mockMvc.perform(get("/api/modules/e01f9925-a559-45a2-8a55-f93dc434c676")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name", is("terraform-docker-mongo"))); + } + + @Test + void findModule_shouldReturnModulesOfOtherTeams_forAdmin() throws Exception { + mockMvc.perform(get("/api/modules/845543d0-20a5-466c-8978-33c9a4661606")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name", is("terraform-docker-mongo-limited"))); + } + + @Test + @WithMockUser("Mary J") + void saveModule_shouldNotBeAccessible_forStandardUsers() throws Exception { + mockMvc.perform(put("/api/modules/test") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"module-test\"}")) + .andExpect(status().isForbidden()); + } + + @Test + void saveModule_shouldBeAccessible_forAdmin() throws Exception { + mockMvc.perform(put("/api/modules/test") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"module-test\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", notNullValue())) + .andExpect(jsonPath("$.name", is("module-test"))); + } + +} \ No newline at end of file diff --git a/src/test/java/io/codeka/gaia/stacks/controller/StackRestControllerIT.java b/src/test/java/io/codeka/gaia/stacks/controller/StackRestControllerIT.java new file mode 100644 index 000000000..f2c3f43b8 --- /dev/null +++ b/src/test/java/io/codeka/gaia/stacks/controller/StackRestControllerIT.java @@ -0,0 +1,115 @@ +package io.codeka.gaia.stacks.controller; + +import io.codeka.gaia.test.MongoContainer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import static org.hamcrest.Matchers.*; +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; + +/** + * Simple integration test that validates the security configuration of the TeamsRestController, and its http routes + */ +@SpringBootTest +@DirtiesContext +@Testcontainers +@AutoConfigureMockMvc +@WithMockUser(value = "admin", roles = "ADMIN") +class StackRestControllerIT { + + @Container + private static MongoContainer mongoContainer = new MongoContainer() + .withScript("src/test/resources/db/00_team.js") + .withScript("src/test/resources/db/10_user.js") + .withScript("src/test/resources/db/20_module.js") + .withScript("src/test/resources/db/30_stack.js"); + + @Autowired + private MockMvc mockMvc; + + @BeforeEach + void setup() { + mongoContainer.resetDatabase(); + } + + @Test + @WithMockUser("Mary J") + void listStacks_shouldReturnLimitedStacks_forStandardUsers() throws Exception { + mockMvc.perform(get("/api/stacks")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0]name", is("mongo-instance-limited"))) + .andExpect(jsonPath("$[0]ownerTeam.id", is("Not Ze Team"))); + } + + @Test + void listStacks_shouldReturnAllStacks_forAdmin() throws Exception { + mockMvc.perform(get("/api/stacks")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(3))) + .andExpect(jsonPath("$..name", contains("mongo-instance-1", "mongo-instance-2", "mongo-instance-limited"))) + .andExpect(jsonPath("$..ownerTeam.id", contains("Ze Team", "Ze Team", "Not Ze Team"))); + } + + @Test + @WithMockUser("Mary J") + void getStacks_shouldReturnStack_forStandardUsers() throws Exception { + mockMvc.perform(get("/api/stacks/845543d0-20a5-466c-8978-33c9a4661606")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name", is("mongo-instance-limited"))) + .andExpect(jsonPath("$.ownerTeam.id", is("Not Ze Team"))) + .andExpect(jsonPath("$.estimatedRunningCost", is(0))); + } + + @Test + @WithMockUser("Mary J") + void getStacks_shouldNotReturnStackOfOtherTeams_forStandardUsers() throws Exception { + mockMvc.perform(get("/api/stacks/5a215b6b-fe53-4afa-85f0-a10175a7f264")) + .andExpect(status().isNotFound()); + } + + @Test + void getStacks_shouldReturnStack_forAdmin() throws Exception { + mockMvc.perform(get("/api/stacks/5a215b6b-fe53-4afa-85f0-a10175a7f264")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name", is("mongo-instance-1"))) + .andExpect(jsonPath("$.ownerTeam.id", is("Ze Team"))) + .andExpect(jsonPath("$.estimatedRunningCost", is(0))); + } + + @Test + @WithMockUser("Mary J") + void saveModule_shouldBeAccessible() throws Exception { + mockMvc.perform(post("/api/stacks") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"stack-test\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", notNullValue())) + .andExpect(jsonPath("$.ownerTeam.id", is("Not Ze Team"))) + .andExpect(jsonPath("$.createdBy.username", is("Mary J"))) + .andExpect(jsonPath("$.createdAt", notNullValue())); + } + + @Test + @WithMockUser("Mary J") + void updateModule_shouldBeAccessible() throws Exception { + mockMvc.perform(put("/api/stacks/test") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"stack-test\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.updatedBy.username", is("Mary J"))) + .andExpect(jsonPath("$.updatedAt", notNullValue())); + } + +} \ No newline at end of file diff --git a/src/test/java/io/codeka/gaia/teams/controller/TeamsRestControllerIT.java b/src/test/java/io/codeka/gaia/teams/controller/TeamsRestControllerIT.java index 57b05371a..f2ec1d98f 100644 --- a/src/test/java/io/codeka/gaia/teams/controller/TeamsRestControllerIT.java +++ b/src/test/java/io/codeka/gaia/teams/controller/TeamsRestControllerIT.java @@ -1,43 +1,38 @@ package io.codeka.gaia.teams.controller; -import io.codeka.gaia.config.SecurityConfig; -import io.codeka.gaia.teams.repository.TeamRepository; import io.codeka.gaia.test.MongoContainer; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.verify; -import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * Simple integration test that validates the security configuration of the TeamsRestController, and its http routes */ -@SpringBootTest(classes={TeamsRestController.class, SecurityConfig.class}) -@AutoConfigureWebMvc +@SpringBootTest +@DirtiesContext +@Testcontainers @AutoConfigureMockMvc @WithMockUser(value = "admin", roles = "ADMIN") class TeamsRestControllerIT { - @MockBean - private TeamRepository teamRepository; + @Container + private static MongoContainer mongoContainer = new MongoContainer() + .withScript("src/test/resources/db/00_team.js"); @Autowired private TeamsRestController teamsRestController; @@ -47,20 +42,21 @@ class TeamsRestControllerIT { @Test @WithMockUser("Mary J") - void teams_shouldNotBeAccessible_forStandardUsers(){ + void teams_shouldNotBeAccessible_forStandardUsers() { assertThrows(AccessDeniedException.class, () -> teamsRestController.teams()); } @Test - void teams_shouldBeAccessible_forAdminUser(){ + void teams_shouldBeAccessible_forAdminUser() { assertDoesNotThrow(() -> teamsRestController.teams()); } @Test void teams_shouldBeExposed_atSpecificUrl() throws Exception { - mockMvc.perform(get("/api/teams")).andExpect(status().isOk()); - - verify(teamRepository).findAll(); + mockMvc.perform(get("/api/teams")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(2))) + .andExpect(jsonPath("$..id", contains("Ze Team", "Not Ze Team"))); } } \ No newline at end of file diff --git a/src/test/java/io/codeka/gaia/teams/controller/UsersRestControllerIT.java b/src/test/java/io/codeka/gaia/teams/controller/UsersRestControllerIT.java index c1e3f735a..18f27a2d7 100644 --- a/src/test/java/io/codeka/gaia/teams/controller/UsersRestControllerIT.java +++ b/src/test/java/io/codeka/gaia/teams/controller/UsersRestControllerIT.java @@ -1,37 +1,40 @@ package io.codeka.gaia.teams.controller; -import io.codeka.gaia.config.SecurityConfig; -import io.codeka.gaia.teams.repository.UserRepository; +import io.codeka.gaia.test.MongoContainer; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.web.servlet.MockMvc; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * Simple integration test that validates the security configuration of the UsersRestController, and its http routes */ -@SpringBootTest(classes={UsersRestController.class, SecurityConfig.class}) -@AutoConfigureWebMvc +@SpringBootTest +@DirtiesContext +@Testcontainers @AutoConfigureMockMvc @WithMockUser(value = "admin", roles = "ADMIN") class UsersRestControllerIT { - @MockBean - private UserRepository userRepository; + @Container + private static MongoContainer mongoContainer = new MongoContainer() + .withScript("src/test/resources/db/00_team.js") + .withScript("src/test/resources/db/10_user.js"); @Autowired private UsersRestController usersRestController; @@ -41,29 +44,34 @@ class UsersRestControllerIT { @Test @WithMockUser("Matthew Bellamy") - void users_shouldNotBeAccessible_forStandardUsers(){ + void users_shouldNotBeAccessible_forStandardUsers() { assertThrows(AccessDeniedException.class, () -> usersRestController.users()); } @Test - void users_shouldBeAccessible_forAdminUser(){ + void users_shouldBeAccessible_forAdminUser() { assertDoesNotThrow(() -> usersRestController.users()); } @Test void users_shouldBeExposed_atSpecificUrl() throws Exception { - mockMvc.perform(get("/api/users")).andExpect(status().isOk()); - - verify(userRepository).findAll(); + mockMvc.perform(get("/api/users")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(2))) + .andExpect(jsonPath("$..username", contains("admin", "Mary J"))) + .andExpect(jsonPath("$..admin", contains(true, false))) + .andExpect(jsonPath("$..team.id", contains("Ze Team", "Not Ze Team"))); } @Test void saveUser_shouldBeExposed_atSpecificUrl() throws Exception { mockMvc.perform(put("/api/users/test") .contentType(MediaType.APPLICATION_JSON) - .content("{\"username\":\"Bob\"}")).andExpect(status().isOk()); - - verify(userRepository).save(any()); + .content("{\"username\":\"Bob\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.username", is("Bob"))) + .andExpect(jsonPath("$.admin", is(false))) + .andExpect(jsonPath("$.team", isEmptyOrNullString())); } } \ No newline at end of file