| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.geode.rest.internal.web.controllers; |
| |
| import static org.apache.geode.test.matchers.JsonEquivalence.jsonEquals; |
| import static org.assertj.core.api.Assertions.assertThat; |
| import static org.hamcrest.Matchers.containsInAnyOrder; |
| import static org.hamcrest.Matchers.is; |
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; |
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head; |
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; |
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; |
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; |
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; |
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
| |
| import java.net.URL; |
| import java.nio.file.Files; |
| import java.nio.file.Paths; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.stream.IntStream; |
| |
| import com.jayway.jsonpath.JsonPath; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.ClassRule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.http.HttpHeaders; |
| import org.springframework.http.MediaType; |
| import org.springframework.mock.web.MockHttpServletRequest; |
| import org.springframework.security.test.context.support.WithMockUser; |
| import org.springframework.test.context.ContextConfiguration; |
| import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; |
| import org.springframework.test.context.web.GenericXmlWebContextLoader; |
| import org.springframework.test.context.web.WebAppConfiguration; |
| import org.springframework.test.context.web.WebMergedContextConfiguration; |
| import org.springframework.test.web.servlet.MockMvc; |
| import org.springframework.test.web.servlet.MvcResult; |
| import org.springframework.test.web.servlet.request.RequestPostProcessor; |
| import org.springframework.test.web.servlet.setup.MockMvcBuilders; |
| import org.springframework.web.context.WebApplicationContext; |
| import org.springframework.web.context.support.GenericWebApplicationContext; |
| |
| import org.apache.geode.cache.CacheLoader; |
| import org.apache.geode.cache.CacheWriter; |
| import org.apache.geode.cache.CacheWriterException; |
| import org.apache.geode.cache.Declarable; |
| import org.apache.geode.cache.EntryEvent; |
| import org.apache.geode.cache.LoaderHelper; |
| import org.apache.geode.cache.Region; |
| import org.apache.geode.cache.RegionDestroyedException; |
| import org.apache.geode.cache.RegionEvent; |
| import org.apache.geode.cache.RegionShortcut; |
| import org.apache.geode.cache.TimeoutException; |
| import org.apache.geode.cache.execute.FunctionService; |
| import org.apache.geode.internal.cache.HttpService; |
| import org.apache.geode.management.internal.RestAgent; |
| import org.apache.geode.pdx.PdxInstance; |
| import org.apache.geode.test.junit.rules.ServerStarterRule; |
| |
| @RunWith(SpringJUnit4ClassRunner.class) |
| @ContextConfiguration(locations = {"classpath*:WEB-INF/geode-servlet.xml"}, |
| loader = TestContextLoader.class) |
| @WebAppConfiguration |
| public class RestAccessControllerTest { |
| |
| private static final String BASE_URL = "http://localhost/v1"; |
| |
| private static final String ORDER1_JSON = "order1.json"; |
| private static final String ORDER1_ARRAY_JSON = "order1-array.json"; |
| private static final String ORDER1_NO_TYPE_JSON = "order1-no-type.json"; |
| private static final String ORDER2_JSON = "order2.json"; |
| private static final String ORDER2_UPDATED_JSON = "order2-updated.json"; |
| private static final String MALFORMED_JSON = "malformed.json"; |
| private static final String CUSTOMER_LIST_JSON = "customer-list.json"; |
| private static final String CUSTOMER_LIST_NO_TYPE_JSON = "customer-list-no-type.json"; |
| private static final String ORDER_CAS_JSON = "order-cas.json"; |
| private static final String ORDER_CAS_OLD_JSON = "order-cas-old.json"; |
| private static final String ORDER_CAS_NEW_JSON = "order-cas-new.json"; |
| private static final String ORDER_CAS_WRONG_OLD_JSON = "order-cas-wrong-old.json"; |
| |
| private static Map<String, String> jsonResources = new HashMap<>(); |
| |
| private static RequestPostProcessor POST_PROCESSOR = new StandardRequestPostProcessor(); |
| |
| private MockMvc mockMvc; |
| |
| private static Region<?, ?> orderRegion; |
| private static Region<?, ?> customerRegion; |
| |
| @ClassRule |
| public static ServerStarterRule rule = new ServerStarterRule() |
| .withProperty("log-level", "warn") |
| .withPDXReadSerialized() |
| .withRegion(RegionShortcut.REPLICATE, "customers") |
| .withRegion(RegionShortcut.REPLICATE, "orders"); |
| |
| @Autowired |
| private WebApplicationContext webApplicationContext; |
| |
| @BeforeClass |
| public static void setupCClass() throws Exception { |
| loadResource(ORDER1_JSON); |
| loadResource(ORDER1_ARRAY_JSON); |
| loadResource(ORDER1_NO_TYPE_JSON); |
| loadResource(ORDER2_JSON); |
| loadResource(MALFORMED_JSON); |
| loadResource(CUSTOMER_LIST_JSON); |
| loadResource(CUSTOMER_LIST_NO_TYPE_JSON); |
| loadResource(ORDER2_UPDATED_JSON); |
| loadResource(ORDER_CAS_JSON); |
| loadResource(ORDER_CAS_OLD_JSON); |
| loadResource(ORDER_CAS_NEW_JSON); |
| loadResource(ORDER_CAS_WRONG_OLD_JSON); |
| |
| RestAgent.createParameterizedQueryRegion(); |
| |
| FunctionService.registerFunction(new AddFreeItemToOrders()); |
| FunctionService.registerFunction(new EchoArgumentFunction()); |
| |
| rule.createRegion(RegionShortcut.REPLICATE_PROXY, "empty", |
| f -> f.setCacheLoader(new SimpleCacheLoader()).setCacheWriter(new SimpleCacheWriter())); |
| |
| customerRegion = rule.getCache().getRegion("customers"); |
| orderRegion = rule.getCache().getRegion("orders"); |
| } |
| |
| private static void loadResource(String name) throws Exception { |
| URL orderCasJson = RestAccessControllerTest.class.getResource(name); |
| jsonResources.put(name, new String(Files.readAllBytes(Paths.get(orderCasJson.toURI())))); |
| } |
| |
| @Before |
| public void setup() { |
| mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); |
| |
| customerRegion.clear(); |
| orderRegion.clear(); |
| } |
| |
| @Test |
| @WithMockUser |
| public void postEntry() throws Exception { |
| mockMvc.perform(post("/v1/orders?key=1") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/orders/1")); |
| |
| mockMvc.perform(post("/v1/orders?key=1") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isConflict()); |
| |
| Order order = (Order) ((PdxInstance) orderRegion.get("1")).getObject(); |
| assertThat(order).as("order should not be null").isNotNull(); |
| } |
| |
| @Test |
| @WithMockUser |
| public void postEntryWithJsonArrayOfOrders() throws Exception { |
| mockMvc.perform(post("/v1/orders?key=1") |
| .content(jsonResources.get(ORDER1_ARRAY_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/orders/1")); |
| |
| mockMvc.perform(post("/v1/orders?key=1") |
| .content(jsonResources.get(ORDER1_ARRAY_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isConflict()); |
| |
| List<PdxInstance> entries = (List<PdxInstance>) orderRegion.get("1"); |
| Order order = (Order) entries.get(0).getObject(); |
| assertThat(order).as("order should not be null").isNotNull(); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPostEntryWithInvalidJson() throws Exception { |
| mockMvc.perform(post("/v1/orders?key=1") |
| .content(jsonResources.get(MALFORMED_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isBadRequest()) |
| .andExpect( |
| jsonPath("$.cause", is("Json doc specified is either not supported or invalid!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPostEntryWithInvalidRegion() throws Exception { |
| mockMvc.perform(post("/v1/unknown?key=1") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPostEntryOnRegionWithDataPolicyEmpty() throws Exception { |
| mockMvc.perform(post("/v1/empty?key=1") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isInternalServerError()) |
| .andExpect( |
| jsonPath("$.message", |
| is("Resource (empty) configuration does not support the requested operation!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failGettingEntryFromUnknownRegion() throws Exception { |
| mockMvc.perform(get("/v1/unknown/10") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failGettingEntryWhenCacheLoaderFails() throws Exception { |
| mockMvc.perform(get("/v1/empty/10") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isInternalServerError()) |
| .andExpect( |
| jsonPath("$.message", |
| is("Server has encountered timeout error while processing this request!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void putEntry() throws Exception { |
| mockMvc.perform(put("/v1/orders/2") |
| .content(jsonResources.get(ORDER2_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Location", BASE_URL + "/orders/2")); |
| |
| mockMvc.perform(put("/v1/orders/2") |
| .content(jsonResources.get(ORDER2_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Location", BASE_URL + "/orders/2")); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutEntryWithInvalidJson() throws Exception { |
| mockMvc.perform(put("/v1/orders/1") |
| .content(jsonResources.get(MALFORMED_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isBadRequest()) |
| .andExpect( |
| jsonPath("$.cause", is("Json doc specified is either not supported or invalid!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutEntryWithInvalidRegion() throws Exception { |
| mockMvc.perform(put("/v1/unknown/1") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutEntryOnRegionWhenCacheWriterFails() throws Exception { |
| mockMvc.perform(put("/v1/empty/1") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isInternalServerError()) |
| .andExpect( |
| jsonPath("$.message", |
| is("Server has encountered CacheWriter error while processing this request!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void putAll() throws Exception { |
| mockMvc.perform( |
| put("/v1/customers/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60") |
| .content(jsonResources.get(CUSTOMER_LIST_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Location", BASE_URL |
| + "/customers/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60")); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutAllWithInvalidJson() throws Exception { |
| mockMvc.perform(put("/v1/customers/1,2,3,4") |
| .content(jsonResources.get(MALFORMED_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isBadRequest()) |
| .andExpect(jsonPath("$.cause", is("JSON document specified in the request is incorrect"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutAllWithInvalidRegion() throws Exception { |
| mockMvc.perform( |
| put("/v1/unknown/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60") |
| .content(jsonResources.get(CUSTOMER_LIST_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutAllWhenCacheWriterFails() throws Exception { |
| mockMvc.perform( |
| put("/v1/empty/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60") |
| .content(jsonResources.get(CUSTOMER_LIST_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isInternalServerError()) |
| .andExpect( |
| jsonPath("$.cause", is("Put request failed as gemfire has thrown an error."))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void putWithReplace() throws Exception { |
| // First time through the key does not exist and we get a 404 |
| mockMvc.perform(put("/v1/orders/2?op=REPLACE") |
| .content(jsonResources.get(ORDER2_UPDATED_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()); |
| |
| // Create an entry that we can subsequently update |
| mockMvc.perform(put("/v1/orders/2") |
| .content(jsonResources.get(ORDER2_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Location", BASE_URL |
| + "/orders/2")); |
| |
| // Do the actual update |
| mockMvc.perform(put("/v1/orders/2?op=REPLACE") |
| .content(jsonResources.get(ORDER2_UPDATED_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Location", BASE_URL |
| + "/orders/2")); |
| |
| // Check the updated value |
| mockMvc.perform(get("/v1/orders/2") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json(jsonResources.get(ORDER2_UPDATED_JSON))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutWithReplaceWithInvalidJson() throws Exception { |
| mockMvc.perform(put("/v1/orders/1?op=REPLACE") |
| .content(jsonResources.get(MALFORMED_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isBadRequest()) |
| .andExpect( |
| jsonPath("$.cause", is("Json doc specified is either not supported or invalid!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutWithReplaceWithInvalidRegion() throws Exception { |
| mockMvc.perform(put("/v1/unknown/1?op=REPLACE") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutWithReplaceFailsOnEmptyRegion() throws Exception { |
| mockMvc.perform(put("/v1/empty/10?op=REPLACE") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isInternalServerError()) |
| .andExpect( |
| jsonPath("$.message", |
| is("Resource (empty) configuration does not support the requested operation!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void putWithCas() throws Exception { |
| // First time through the key does not exist and we get a 404 |
| mockMvc.perform(put("/v1/orders/3?op=CAS") |
| .content(jsonResources.get(ORDER_CAS_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) // This is wrong!!! |
| .andExpect(header().string("Location", BASE_URL |
| + "/orders/3")); |
| |
| // Create an entry that we can subsequently update |
| mockMvc.perform(put("/v1/orders/3") |
| .content(jsonResources.get(ORDER_CAS_OLD_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Location", BASE_URL |
| + "/orders/3")); |
| |
| // Check the value |
| mockMvc.perform(get("/v1/orders/3") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json(jsonResources.get(ORDER_CAS_OLD_JSON))); |
| |
| // Try and update with an incorrect old value |
| mockMvc.perform(put("/v1/orders/3?op=CAS") |
| .content(jsonResources.get(ORDER_CAS_WRONG_OLD_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isConflict()) |
| .andExpect(header().string("Location", BASE_URL |
| + "/orders/3")) |
| .andExpect(content().json(jsonResources.get(ORDER_CAS_OLD_JSON))); |
| |
| // Check that the value has not changed |
| mockMvc.perform(get("/v1/orders/3") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json(jsonResources.get(ORDER_CAS_OLD_JSON))); |
| |
| // Do the actual update |
| mockMvc.perform(put("/v1/orders/3?op=CAS") |
| .content(jsonResources.get(ORDER_CAS_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Location", BASE_URL + "/orders/3")); |
| |
| // Check the updated value |
| mockMvc.perform(get("/v1/orders/3") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json(jsonResources.get(ORDER_CAS_NEW_JSON))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutWithCasWithInvalidJson() throws Exception { |
| mockMvc.perform(put("/v1/orders/1?op=CAS") |
| .content(jsonResources.get(MALFORMED_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isBadRequest()) |
| .andExpect( |
| jsonPath("$.cause", is("Json doc specified in request body is invalid!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutWithCasWithInvalidRegion() throws Exception { |
| mockMvc.perform(put("/v1/unknown/10?op=CAS") |
| .content(jsonResources.get(ORDER_CAS_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPutWithCasFailsOnEmptyRegion() throws Exception { |
| mockMvc.perform(put("/v1/empty/10?op=CAS") |
| .content(jsonResources.get(ORDER_CAS_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isInternalServerError()) |
| .andExpect( |
| jsonPath("$.message", |
| is("Resource (empty) configuration does not support the requested operation!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getRegions() throws Exception { |
| mockMvc.perform(get("/v1") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect( |
| jsonPath("$.regions[*].name", containsInAnyOrder("customers", "orders", "empty"))) |
| .andExpect( |
| jsonPath("$.regions[*].type", containsInAnyOrder("REPLICATE", "REPLICATE", "EMPTY"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void postRegions() throws Exception { |
| mockMvc.perform(post("/v1") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isMethodNotAllowed()) |
| .andExpect(jsonPath("$.cause", is("Request method 'POST' not supported"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getCustomers() throws Exception { |
| putAll(); |
| mockMvc.perform(get("/v1/customers?limit=ALL") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.customers", jsonEquals(jsonResources.get(CUSTOMER_LIST_JSON)))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getFromInvalidRegion() throws Exception { |
| putAll(); |
| mockMvc.perform(get("/v1/unknown") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getCustomersWithLimit() throws Exception { |
| putAll(); |
| mockMvc.perform(get("/v1/customers?limit=10") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.customers.length()", is(10))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getAllKeys() throws Exception { |
| putAll(); |
| mockMvc.perform(get("/v1/customers/keys") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.keys", |
| containsInAnyOrder(IntStream.rangeClosed(1, 60).mapToObj(i -> i + "").toArray()))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getAllKeysFromInvalidRegion() throws Exception { |
| mockMvc.perform(get("/v1/unknown/keys") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void failPostAllKeys() throws Exception { |
| mockMvc.perform(post("/v1/unknown/keys") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isMethodNotAllowed()) |
| .andExpect(jsonPath("$.cause", is("Request method 'POST' not supported"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getSpecificKeys() throws Exception { |
| putAll(); |
| mockMvc.perform(get("/v1/customers/1,2,3,4,5") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect( |
| jsonPath("$.customers[*].customerId", containsInAnyOrder(101, 102, 103, 104, 105))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getSpecificKeysFromUnknownRegion() throws Exception { |
| mockMvc.perform(get("/v1/unknown/1,2,3,4,5") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()) |
| .andExpect( |
| jsonPath("$.cause", is("The Region identified by name (unknown) could not be found!"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void deleteSingleKey() throws Exception { |
| putAll(); |
| mockMvc.perform(delete("/v1/customers/1") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void deleteFromInvalidRegion() throws Exception { |
| mockMvc.perform(delete("/v1/unknown/1") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void deleteMultipleKeys() throws Exception { |
| putAll(); |
| mockMvc.perform(delete("/v1/customers/2,3,4,5") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void deleteAllKeys() throws Exception { |
| putAll(); |
| mockMvc.perform(delete("/v1/customers") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| |
| mockMvc.perform(head("/v1/customers") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Resource-Count", "0")); |
| } |
| |
| @Test |
| @WithMockUser |
| public void deleteMultipleKeysFromInvalidRegion() throws Exception { |
| mockMvc.perform(delete("/v1/unknown/2,3,4,5") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void deleteMultipleKeysFromEmptyRegion() throws Exception { |
| mockMvc.perform(delete("/v1/empty/2,3,4,5") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void createQueries() throws Exception { |
| deleteAllQueries(); |
| |
| mockMvc.perform(post( |
| "/v1/queries?id=selectOrder&q=SELECT DISTINCT o FROM /orders o, o.items item WHERE item.quantity > $1 AND item.totalPrice > $2") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/queries/selectOrder")); |
| |
| mockMvc.perform( |
| post("/v1/queries?id=selectCustomer&q=SELECT c FROM /customers c WHERE c.customerId = $1") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/queries/selectCustomer")); |
| |
| mockMvc.perform(post( |
| "/v1/queries?id=selectHighRoller&q=SELECT DISTINCT c FROM /customers c, /orders o, o.items item WHERE item.totalprice > $1 AND c.customerId = o.customerId") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/queries/selectHighRoller")); |
| |
| mockMvc.perform(get("/v1/queries") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect( |
| jsonPath("$.queries[*].id", |
| containsInAnyOrder("selectOrder", "selectCustomer", "selectHighRoller"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void executeQueryWithParams() throws Exception { |
| String QUERY_ARGS = |
| "[{\"@type\": \"int\", \"@value\": 2}, {\"@type\": \"double\", \"@value\": 150.00}]"; |
| |
| postEntry(); // order 1 |
| putEntry(); // order 2 |
| createQueries(); |
| mockMvc.perform(post("/v1/queries/selectOrder") |
| .with(POST_PROCESSOR) |
| .content(QUERY_ARGS)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.[0]", jsonEquals(jsonResources.get(ORDER1_NO_TYPE_JSON)))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void executeAdhocQuery() throws Exception { |
| putAll(); |
| mockMvc.perform(get("/v1/queries/adhoc?q=SELECT * FROM /customers LIMIT 100") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json(jsonResources.get(CUSTOMER_LIST_NO_TYPE_JSON))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void putAndUpdateQuery() throws Exception { |
| final String QUERY_ARGS = "[{\"@type\": \"int\", \"@value\": 20}," |
| + "{\"@type\": \"int\", \"@value\": 120}," |
| + "{\"@type\": \"int\", \"@value\": 130}]"; |
| |
| deleteAllQueries(); |
| putAll(); // Create customers |
| mockMvc.perform( |
| post("/v1/queries?id=testQuery&q=SELECT DISTINCT c from /customers c where lastName=$1") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/queries/testQuery")); |
| |
| mockMvc.perform( |
| put("/v1/queries/testQuery?q=SELECT DISTINCT c from /customers c where customerId IN SET ($1, $2, $3)") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| |
| mockMvc.perform(post("/v1/queries/testQuery") |
| .content(QUERY_ARGS) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.[*].customerId", containsInAnyOrder(120, 130))) |
| .andExpect(jsonPath("$.[*].firstName", containsInAnyOrder("Preeti", "Varun"))) |
| .andExpect(jsonPath("$.[*].lastName", containsInAnyOrder("Kumari", "Agrawal"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void deleteQuery() throws Exception { |
| mockMvc.perform( |
| post("/v1/queries?id=myQuery&q=SELECT DISTINCT c from /customers c where lastName=$1") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/queries/myQuery")); |
| |
| mockMvc.perform(delete("/v1/queries/myQuery") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| |
| mockMvc.perform(get("/v1/queries/myQuery") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()); |
| |
| mockMvc.perform(delete("/v1/queries/myQuery") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void putUnknownQuery() throws Exception { |
| mockMvc.perform( |
| put("/v1/queries/unknown?q=SELECT DISTINCT c from /customers c where customerId IN SET ($1, $2, $3)") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isNotFound()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void createQueryFromRequestBody() throws Exception { |
| deleteAllQueries(); |
| |
| mockMvc.perform(post("/v1/queries?id=testQuery") |
| .content("SELECT * from /customers") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()) |
| .andExpect(header().string("Location", BASE_URL + "/queries/testQuery")); |
| |
| mockMvc.perform(get("/v1/queries") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.queries[*].id", containsInAnyOrder("testQuery"))) |
| .andExpect(jsonPath("$.queries[*].oql", containsInAnyOrder("SELECT * from /customers"))); |
| |
| mockMvc.perform(put("/v1/queries/testQuery") |
| .content("SELECT * from /orders") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| |
| mockMvc.perform(get("/v1/queries") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.queries[*].id", containsInAnyOrder("testQuery"))) |
| .andExpect(jsonPath("$.queries[*].oql", containsInAnyOrder("SELECT * from /orders"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void listFunctions() throws Exception { |
| mockMvc.perform(get("/v1/functions")) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.functions", |
| containsInAnyOrder("AddFreeItemToOrders", "EchoArgumentFunction"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void executeFunction() throws Exception { |
| final String FUNCTION_ARGS = "[{\"@type\": \"double\", \"@value\": 210}," |
| + "{\"@type\": \"org.apache.geode.rest.internal.web.controllers.Item\"," |
| + "\"itemNo\": 599, \"description\": \"Part X Free on Bumper Offer\"," |
| + "\"quantity\": 2, \"unitprice\": 5, \"totalprice\": 10.00}]"; |
| |
| putEntry(); // order 2 |
| mockMvc.perform(post("/v1/functions/AddFreeItemToOrders?onRegion=orders") |
| .content(FUNCTION_ARGS) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| |
| mockMvc.perform(get("/v1/orders/2") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(jsonPath("$.items[*].itemNo", containsInAnyOrder(1, 2, 599))) |
| .andExpect(jsonPath("$.items[*].description", |
| containsInAnyOrder("Product-3", "Product-4", "Part X Free on Bumper Offer"))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void executeNoArgFunctionWithInvalidArg() throws Exception { |
| mockMvc.perform(post("/v1/functions/EchoArgumentFunction") |
| .content("{\"type\": \"int\"}") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json("[{}]")); |
| } |
| |
| @Test |
| @WithMockUser |
| public void executeNoArgFunctionWithEmptyObject() throws Exception { |
| mockMvc.perform(post("/v1/functions/EchoArgumentFunction") |
| .content("[{ }]") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json("[{}]")); |
| } |
| |
| @Test |
| @WithMockUser |
| public void executeNoArgFunctionWithEmptyArray() throws Exception { |
| mockMvc.perform(post("/v1/functions/EchoArgumentFunction") |
| .content("[]") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json("[[]]")); |
| } |
| |
| @Test |
| @WithMockUser |
| public void executeNoArgFunctionWithNoContent() throws Exception { |
| mockMvc.perform(post("/v1/functions/EchoArgumentFunction") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json("[null]")); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getEntryAfterCreation() throws Exception { |
| mockMvc.perform(post("/v1/orders?key=10") |
| .content(jsonResources.get(ORDER1_JSON)) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isCreated()); |
| |
| mockMvc.perform(get("/v1/orders/10") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(content().json(jsonResources.get(ORDER1_JSON))); |
| } |
| |
| @Test |
| @WithMockUser |
| public void getPing() throws Exception { |
| mockMvc.perform(get("/v1/ping") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void headPing() throws Exception { |
| mockMvc.perform(head("/v1/ping") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| } |
| |
| @Test |
| @WithMockUser |
| public void headCustomers() throws Exception { |
| putAll(); // load customers |
| mockMvc.perform(head("/v1/customers") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andExpect(header().string("Resource-Count", "60")); |
| } |
| |
| |
| private void deleteAllQueries() throws Exception { |
| MvcResult result = mockMvc.perform(get("/v1/queries") |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()) |
| .andReturn(); |
| |
| String content = result.getResponse().getContentAsString(); |
| List<String> ids = JsonPath.read(content, "$.queries[*].id"); |
| |
| for (String id : ids) { |
| mockMvc.perform(delete("/v1/queries/" + id) |
| .with(POST_PROCESSOR)) |
| .andExpect(status().isOk()); |
| } |
| } |
| |
| private static class StandardRequestPostProcessor implements RequestPostProcessor { |
| @Override |
| public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { |
| request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON); |
| request.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); |
| return request; |
| } |
| } |
| |
| static class SimpleCacheLoader implements CacheLoader, Declarable { |
| @Override |
| public Object load(LoaderHelper helper) { |
| // throws TimeoutException |
| throw new TimeoutException("Could not load entry. Request timed out."); |
| } |
| |
| @Override |
| public void close() { |
| // nothing |
| } |
| |
| @Override |
| public void init(Properties props) { |
| // nothing |
| } |
| } |
| |
| static class SimpleCacheWriter implements CacheWriter { |
| @Override |
| public void close() { |
| // nothing |
| } |
| |
| @Override |
| public void beforeUpdate(EntryEvent event) throws CacheWriterException { |
| // nothing |
| } |
| |
| @Override |
| public void beforeCreate(EntryEvent event) throws CacheWriterException { |
| throw new CacheWriterException("Put request failed as gemfire has thrown an error."); |
| } |
| |
| @Override |
| public void beforeDestroy(EntryEvent event) throws CacheWriterException { |
| throw new RegionDestroyedException("Region has already been destroyed.", "dummyRegion"); |
| } |
| |
| @Override |
| public void beforeRegionDestroy(RegionEvent event) throws CacheWriterException { |
| // nothing |
| } |
| |
| @Override |
| public void beforeRegionClear(RegionEvent event) throws CacheWriterException { |
| // nothing |
| } |
| } |
| } |
| |
| |
| class TestContextLoader extends GenericXmlWebContextLoader { |
| @Override |
| protected void loadBeanDefinitions(GenericWebApplicationContext context, |
| WebMergedContextConfiguration webMergedConfig) { |
| super.loadBeanDefinitions(context, webMergedConfig); |
| context.getServletContext().setAttribute(HttpService.SECURITY_SERVICE_SERVLET_CONTEXT_PARAM, |
| RestAccessControllerTest.rule.getCache().getSecurityService()); |
| } |
| |
| } |