blob: 681d3d02f1311ee6619ddcc88088bc8d78a5c28b [file] [log] [blame]
/*
* 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.CoreMatchers.containsString;
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.cache.internal.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());
FunctionService.registerFunction(new GetOrderDescriptionFunction());
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",
"GetOrderDescriptionFunction")));
}
@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 executeFunctionWithFilter() throws Exception {
final String FUNCTION_ARGS = "[{\"@type\": \"String\", \"@value\": \"argument\"}]";
putEntry(); // order 2
mockMvc.perform(post("/v1/functions/GetOrderDescriptionFunction?onRegion=orders&filter=2")
.content(FUNCTION_ARGS)
.with(POST_PROCESSOR))
.andExpect(status().isOk())
.andExpect(content().string(containsString("Purchase order for company - B")));
}
@Test
@WithMockUser
public void executeFunctionWithFilterKeyNotFound() throws Exception {
final String FUNCTION_ARGS = "[{\"@type\": \"String\", \"@value\": \"argument\"}]";
putEntry(); // order 2
mockMvc.perform(post("/v1/functions/GetOrderDescriptionFunction?onRegion=orders&filter=1")
.content(FUNCTION_ARGS)
.with(POST_PROCESSOR))
.andExpect(status().isInternalServerError())
.andExpect(
jsonPath("$.message",
is("Server has encountered an error while processing function execution!")));
}
@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());
}
}